Webhook events contain personal data. An IP address is personal data under GDPR. A device type combined with a platform and a timestamp can contribute to a fingerprint. Campaign attribution data, when linked to a user account, becomes part of that user's profile.
If you're processing Tolinku webhook events and storing the data, you have compliance obligations. This guide covers the practical steps: what data is in the payload, what the regulations require, and how to design your webhook pipeline to meet those requirements without sacrificing the analytics value of the data.
This isn't legal advice. Consult a lawyer for your specific situation. This is engineering guidance for building compliant systems.
The webhooks page with create form, webhook list, and delivery log.
What Personal Data Is in the Webhook Payload
Here's what each event carries and its privacy classification:
| Field | Example | Personal Data? | Notes |
|---|---|---|---|
data.ip |
203.0.113.42 |
Yes (GDPR, CCPA) | Directly identifies a network; indirectly identifies a person |
data.platform |
ios |
Weak identifier | Not personal alone; contributes to fingerprinting when combined |
data.device_type |
mobile |
Weak identifier | Same as above |
data.campaign |
summer-sale |
No | Your internal campaign identifier |
data.prefix |
go |
No | Route configuration data |
data.token |
promo-code |
Depends | If it maps to a specific user (referral token), it's personal data |
data.hostname |
links.example.com |
No | Your domain |
timestamp |
ISO 8601 | Contributes | Timestamps narrow identification when combined with other fields |
GDPR Requirements
If you process data from EU/EEA residents, GDPR applies. Key requirements for webhook data:
Lawful Basis
You need a lawful basis for processing the data. For deep link analytics, the most common bases are:
- Legitimate interest (Article 6(1)(f)): You have a legitimate business interest in understanding how users interact with your links. This is typically the basis for analytics and fraud detection.
- Consent (Article 6(1)(a)): If you're using the data for marketing purposes (targeting, profiling), you likely need explicit consent.
Data Minimization
Collect only what you need. If your analytics only requires country-level geo data, don't store the full IP address. If you only need to know the platform (iOS vs. Android), don't store the device type.
Storage Limitation
Don't keep personal data longer than necessary. Raw webhook events with IP addresses should have a retention policy.
Right to Erasure
If a user requests deletion of their data under Article 17, you must be able to find and delete their webhook event records. This is challenging because webhook events are often stored by IP, not by user ID. Plan for this by maintaining a mapping between user accounts and the IPs/tokens associated with their events.
CCPA Requirements
If you process data from California residents, CCPA applies. The requirements overlap with GDPR but have distinct elements:
- Right to know: Users can request what personal information you've collected about them
- Right to delete: Users can request deletion of their personal information
- Right to opt-out: Users can opt out of the "sale" of their personal information
- No discrimination: You can't treat users differently for exercising their rights
For webhook data, the most relevant requirement is the right to delete. If you store IP addresses or can link webhook events to a specific user, you need a mechanism to delete those records on request.
Practical Implementation
1. IP Anonymization
The simplest compliance step: don't store raw IP addresses. Anonymize them before writing to your database.
function anonymizeIP(ip: string): string {
if (ip.includes(':')) {
// IPv6: zero out the last 80 bits
const parts = ip.split(':');
return parts.slice(0, 3).join(':') + ':0:0:0:0:0';
}
// IPv4: zero out the last octet
const parts = ip.split('.');
return `${parts[0]}.${parts[1]}.${parts[2]}.0`;
}
async function storeEvent(event: any) {
const anonymizedData = {
...event.data,
ip: event.data.ip ? anonymizeIP(event.data.ip) : null,
};
await db.query(
'INSERT INTO webhook_events (event_type, timestamp, data) VALUES ($1, $2, $3)',
[event.event, event.timestamp, JSON.stringify(anonymizedData)]
);
}
This preserves geo-level analytics (the first three octets of an IPv4 address are enough for country/region lookup) while removing the ability to identify a specific household or device.
Important: Do your geo-enrichment (IP to country/region) before anonymization. Once the IP is anonymized, you lose precision.
async function processEvent(event: any) {
// Step 1: Enrich with geo data (using full IP)
const geo = lookupGeo(event.data.ip);
// Step 2: Anonymize the IP
const anonymizedData = {
...event.data,
ip: anonymizeIP(event.data.ip),
country: geo.country,
region: geo.region,
};
// Step 3: Store the anonymized event
await storeAnonymizedEvent(event.event, event.timestamp, anonymizedData);
}
2. Data Retention
Set retention periods and enforce them automatically.
-- Delete raw webhook events older than 90 days
DELETE FROM webhook_events
WHERE event_timestamp < NOW() - INTERVAL '90 days';
-- Keep aggregated analytics indefinitely (no personal data)
-- Aggregated tables contain counts by campaign, platform, country, etc.
Run this as a daily cron job or scheduled database task.
Recommended retention periods:
| Data Type | Retention | Reason |
|---|---|---|
| Raw events with anonymized IPs | 90 days | Enough for campaign analysis and fraud investigation |
| Aggregated analytics (no PII) | Indefinite | No personal data; safe to keep |
| Fraud flags with raw IPs | 30 days | Needed for active fraud investigation, then anonymize |
| Dedup records (event hashes) | 7 days | Only needed for retry deduplication |
3. Consent Management
If you use webhook data for marketing (not just analytics), integrate with your consent management platform (CMP).
async function processEvent(event: any) {
// For referral events, check if the referrer has consented to marketing data processing
if (event.event.startsWith('referral.')) {
const referrerToken = event.data.referrer_token;
const hasConsent = await checkMarketingConsent(referrerToken);
if (!hasConsent) {
// Store anonymized event for basic analytics only
await storeAnonymizedEvent(event);
return;
}
}
// Full processing for consented users
await processWithFullData(event);
}
4. Right to Erasure Implementation
Build a deletion endpoint that removes all webhook data associated with a user.
async function handleDeletionRequest(userId: string) {
// Find all tokens and IPs associated with this user
const userTokens = await db.query(
'SELECT referral_token FROM users WHERE id = $1',
[userId]
);
const tokens = userTokens.rows.map(r => r.referral_token);
// Delete webhook events associated with these tokens
if (tokens.length > 0) {
await db.query(
'DELETE FROM webhook_events WHERE data->>\'referrer_token\' = ANY($1)',
[tokens]
);
}
// Delete fraud flags
await db.query(
'DELETE FROM fraud_flags WHERE event_data->\'data\'->>\'referrer_token\' = ANY($1)',
[tokens]
);
console.log(`Deleted webhook data for user ${userId}: ${tokens.length} tokens`);
}
Transport Security
Webhook data in transit must be protected:
- HTTPS only: Tolinku delivers webhooks over HTTPS. Your endpoint must have a valid SSL certificate.
- Signature verification: Always verify the
X-Webhook-Signatureheader to ensure the payload hasn't been tampered with. See the webhook security guide. - Secret rotation: Rotate your webhook signing secret periodically. When you create a new secret in the Tolinku dashboard, update your receiver's environment variable.
Storage Security
- Encrypt at rest: Use database-level encryption (PostgreSQL's pgcrypto, AWS RDS encryption, etc.) for tables containing webhook data.
- Access control: Limit database access to the webhook processing service. Don't give your analytics dashboard direct access to raw IP data.
- Audit logging: Log who accesses webhook data and when. This is required by GDPR for accountability (Article 5(2)).
Vendor Agreements
If you forward webhook data to third-party services (analytics platforms, CRM systems, email providers), you need data processing agreements (DPAs) with those vendors.
Common destinations that need DPAs:
- Analytics tools (Amplitude, Mixpanel, Segment)
- CRM systems (HubSpot, Salesforce)
- Email platforms (SendGrid, Mailchimp)
- Cloud infrastructure (AWS, Google Cloud)
Most major SaaS vendors offer DPAs as part of their terms of service. Request them before forwarding webhook data.
Compliance Checklist
Use this checklist when building or reviewing your webhook pipeline:
- Webhook endpoint uses HTTPS with a valid certificate
- Signature verification is implemented and tested
- IP addresses are anonymized before long-term storage
- Geo-enrichment happens before IP anonymization
- Data retention policy is defined and automated
- Deletion request handler exists and is tested
- Consent status is checked before marketing data processing
- DPAs are in place with all third-party data processors
- Access to raw webhook data is restricted and audited
- Webhook signing secret is stored securely (environment variable, not code)
For the webhook security implementation, see the webhook security guide. For monitoring your webhook pipeline, see the delivery monitoring guide.
Get deep linking tips in your inbox
One email per week. No spam.