GDPR Compliance Guide for Developers
Introduction
GDPR (General Data Protection Regulation) protects EU citizen data. This guide covers GDPR principles, user rights, consent management, data protection by design, breach notification, and practical implementation for developers.
1. GDPR Core Principles
# 7 Key GDPR Principles
1. Lawfulness, fairness and transparency
- Process data legally and transparently
- Inform users how their data is used
2. Purpose limitation
- Collect data for specific, explicit purposes
- Don't use data for incompatible purposes
3. Data minimization
- Collect only necessary data
- Don't collect "just in case"
4. Accuracy
- Keep data accurate and up to date
- Allow users to correct inaccuracies
5. Storage limitation
- Keep data only as long as necessary
- Define retention periods
6. Integrity and confidentiality
- Protect data with appropriate security
- Prevent unauthorized access
7. Accountability
- Demonstrate compliance
- Document processes and decisions
# Legal bases for processing
1. Consent - User gives clear permission
2. Contract - Necessary for contract performance
3. Legal obligation - Required by law
4. Vital interests - Protect life
5. Public task - Carry out official function
6. Legitimate interests - Your interests (with balancing test)
2. User Rights Implementation
// Right to Access (Article 15)
// User can request all their data
app.get('/api/gdpr/data-export', auth, async (req, res) => {
const userId = req.user.id;
// Gather all user data
const user = await User.findById(userId);
const orders = await Order.find({ userId });
const activities = await Activity.find({ userId });
const exportData = {
personal_info: {
email: user.email,
name: user.name,
created_at: user.createdAt
},
orders: orders.map(o => ({
id: o.id,
date: o.date,
total: o.total,
items: o.items
})),
activity_log: activities.map(a => ({
action: a.action,
timestamp: a.timestamp,
ip: a.ip
}))
};
res.json(exportData);
});
// Right to Erasure / "Right to be Forgotten" (Article 17)
app.delete('/api/gdpr/delete-account', auth, async (req, res) => {
const userId = req.user.id;
// Anonymize or delete data
await User.findByIdAndUpdate(userId, {
email: `deleted_${userId}@example.com`,
name: 'Deleted User',
deletedAt: new Date(),
gdprDeleted: true
});
// Optionally delete related data
await Order.updateMany({ userId }, { userDeleted: true });
await Activity.deleteMany({ userId });
// Keep data required for legal/accounting (e.g., orders)
// but anonymize personal information
res.json({ message: 'Account deleted successfully' });
});
// Right to Rectification (Article 16)
app.patch('/api/users/me', auth, async (req, res) => {
const { name, email, phone } = req.body;
const user = await User.findByIdAndUpdate(
req.user.id,
{ name, email, phone },
{ new: true }
);
res.json(user);
});
// Right to Data Portability (Article 20)
app.get('/api/gdpr/export-json', auth, async (req, res) => {
const data = await gatherUserData(req.user.id);
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Disposition', 'attachment; filename=my-data.json');
res.json(data);
});
app.get('/api/gdpr/export-csv', auth, async (req, res) => {
const data = await gatherUserData(req.user.id);
const csv = convertToCSV(data);
res.setHeader('Content-Type', 'text/csv');
res.setHeader('Content-Disposition', 'attachment; filename=my-data.csv');
res.send(csv);
});
// Right to Object (Article 21)
app.post('/api/gdpr/object-processing', auth, async (req, res) => {
await User.findByIdAndUpdate(req.user.id, {
marketingConsent: false,
profilingConsent: false,
dataProcessingObjection: true
});
res.json({ message: 'Your objection has been recorded' });
});
// Right to Restrict Processing (Article 18)
app.post('/api/gdpr/restrict-processing', auth, async (req, res) => {
await User.findByIdAndUpdate(req.user.id, {
processingRestricted: true,
restrictionReason: req.body.reason
});
res.json({ message: 'Processing restricted' });
});
3. Consent Management
// Consent database schema
const consentSchema = new Schema({
userId: { type: ObjectId, ref: 'User', required: true },
purposes: [{
type: { type: String, required: true }, // 'essential', 'analytics', 'marketing'
consented: { type: Boolean, required: true },
timestamp: { type: Date, required: true },
method: String, // 'explicit', 'implied'
version: String // Privacy policy version
}],
ipAddress: String,
userAgent: String
});
// Cookie consent banner implementation
class ConsentManager {
constructor() {
this.consent = this.loadConsent();
}
loadConsent() {
const stored = localStorage.getItem('gdpr_consent');
return stored ? JSON.parse(stored) : null;
}
hasConsent(purpose) {
return this.consent?.purposes?.[purpose] === true;
}
async saveConsent(purposes) {
const consent = {
purposes,
timestamp: new Date().toISOString(),
version: '1.0'
};
localStorage.setItem('gdpr_consent', JSON.stringify(consent));
this.consent = consent;
// Send to server
await fetch('/api/consent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(consent)
});
// Initialize allowed services
this.initializeServices();
}
initializeServices() {
if (this.hasConsent('analytics')) {
this.initAnalytics();
}
if (this.hasConsent('marketing')) {
this.initMarketing();
}
}
withdrawConsent(purpose) {
if (this.consent) {
this.consent.purposes[purpose] = false;
this.saveConsent(this.consent.purposes);
}
}
}
// React consent banner component
function CookieConsent() {
const [show, setShow] = useState(true);
const [preferences, setPreferences] = useState({
essential: true, // Always true, can't be disabled
analytics: false,
marketing: false
});
const handleAcceptAll = () => {
consentManager.saveConsent({
essential: true,
analytics: true,
marketing: true
});
setShow(false);
};
const handleRejectNonEssential = () => {
consentManager.saveConsent({
essential: true,
analytics: false,
marketing: false
});
setShow(false);
};
const handleSavePreferences = () => {
consentManager.saveConsent(preferences);
setShow(false);
};
if (!show) return null;
return (
Cookie Settings
We use cookies to improve your experience.
);
}
4. Data Protection by Design
// Pseudonymization
class Pseudonymizer {
constructor(secret) {
this.secret = secret;
}
pseudonymize(identifier) {
return crypto
.createHmac('sha256', this.secret)
.update(identifier)
.digest('hex');
}
// Store pseudonymized reference
async storeAnalytics(userId, event) {
const pseudoId = this.pseudonymize(userId);
await Analytics.create({
pseudoId, // Not directly identifiable
event,
timestamp: new Date()
});
}
}
// Data encryption at rest
const sensitiveDataSchema = new Schema({
userId: ObjectId,
// Encrypted fields
ssn: { type: String, encrypted: true },
creditCard: { type: String, encrypted: true },
// Regular fields
email: String
});
// Automatic data retention
class DataRetentionManager {
async enforceRetentionPolicies() {
const policies = [
{
collection: 'ActivityLogs',
retentionDays: 90,
dateField: 'timestamp'
},
{
collection: 'Sessions',
retentionDays: 30,
dateField: 'createdAt'
},
{
collection: 'DeletedUsers',
retentionDays: 365,
dateField: 'deletedAt'
}
];
for (const policy of policies) {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - policy.retentionDays);
const result = await db.collection(policy.collection).deleteMany({
[policy.dateField]: { $lt: cutoffDate }
});
console.log(`Deleted ${result.deletedCount} records from ${policy.collection}`);
}
}
}
// Run daily
cron.schedule('0 2 * * *', async () => {
const manager = new DataRetentionManager();
await manager.enforceRetentionPolicies();
});
// Privacy by default
const userSchema = new Schema({
email: { type: String, required: true },
// Default to most private settings
profileVisibility: { type: String, default: 'private' },
showEmail: { type: Boolean, default: false },
allowMessaging: { type: Boolean, default: false },
// Opt-in for marketing
marketingConsent: { type: Boolean, default: false },
thirdPartySharing: { type: Boolean, default: false }
});
5. Data Breach Notification
// Breach detection and notification system
class BreachNotificationSystem {
async detectBreach(incident) {
// Log incident
await Incident.create({
type: incident.type,
severity: incident.severity,
affectedUsers: incident.affectedUsers,
dataTypes: incident.dataTypes,
timestamp: new Date()
});
// Assess if reportable (72 hours to DPA)
const isReportable = this.assessReportability(incident);
if (isReportable) {
await this.notifyDPA(incident);
await this.notifyAffectedUsers(incident);
}
return { reported: isReportable };
}
assessReportability(incident) {
// Breach is reportable if:
// - Involves personal data
// - Likely to result in risk to rights and freedoms
// - High volume of affected users
// - Sensitive data categories
const sensitiveDataTypes = ['health', 'financial', 'biometric'];
const hasSensitiveData = incident.dataTypes.some(t =>
sensitiveDataTypes.includes(t)
);
return incident.affectedUsers > 100 || hasSensitiveData;
}
async notifyDPA(incident) {
// Notify Data Protection Authority within 72 hours
const notification = {
organization: 'Company Name',
dpo: 'dpo@company.com',
incidentDate: incident.timestamp,
dataTypes: incident.dataTypes,
affectedCount: incident.affectedUsers,
riskAssessment: incident.riskAssessment,
mitigationMeasures: incident.mitigationMeasures
};
// Send to appropriate DPA
await this.sendToDPA(notification);
console.log('DPA notified of breach');
}
async notifyAffectedUsers(incident) {
// Notify users without undue delay if high risk
if (incident.severity === 'high') {
const affectedUsers = await User.find({
_id: { $in: incident.affectedUsers }
});
for (const user of affectedUsers) {
await this.sendBreachNotification(user, incident);
}
}
}
async sendBreachNotification(user, incident) {
const email = {
to: user.email,
subject: 'Important Security Notification',
body: `
We are writing to inform you of a security incident that may have
affected your personal data.
What happened: ${incident.description}
What data was affected: ${incident.dataTypes.join(', ')}
What we're doing: ${incident.mitigationMeasures}
What you should do: ${incident.userActions}
For questions, contact: privacy@company.com
`
};
await sendEmail(email);
}
}
// Incident response checklist
const incidentResponse = {
immediate: [
'Contain the breach',
'Assess scope and severity',
'Preserve evidence',
'Document everything'
],
within_24_hours: [
'Notify internal stakeholders',
'Begin forensic investigation',
'Assess legal obligations',
'Prepare notification templates'
],
within_72_hours: [
'Notify DPA if required',
'Notify affected individuals if high risk',
'Implement additional security measures'
],
ongoing: [
'Complete investigation',
'Update security policies',
'Conduct training',
'Review and improve processes'
]
};
6. Privacy Policy & Documentation
// Privacy policy requirements
Privacy Policy Must Include:
1. Identity and contact details of controller
2. Contact details of DPO (if applicable)
3. Purposes of processing
4. Legal basis for processing
5. Recipients of data
6. International transfers (if applicable)
7. Retention periods
8. User rights
9. Right to withdraw consent
10. Right to lodge complaint with DPA
11. Source of data (if not from user)
12. Automated decision-making/profiling
// Data Processing Agreement (DPA) for processors
const dpaTemplate = {
parties: {
controller: 'Company Name',
processor: 'Service Provider'
},
processingDetails: {
purpose: 'Email delivery',
dataTypes: ['email addresses', 'names'],
dataSubjects: 'registered users',
duration: 'duration of service agreement'
},
obligations: [
'Process data only on documented instructions',
'Ensure confidentiality of personnel',
'Implement appropriate security measures',
'Assist with data subject requests',
'Assist with security incidents',
'Delete or return data after service ends',
'Make information available for audits'
],
subprocessors: [
{ name: 'AWS', service: 'hosting', location: 'EU' }
]
};
// Record of Processing Activities (ROPA)
const ropaTemplate = {
activity: 'User registration and authentication',
purpose: 'Create and maintain user accounts',
legalBasis: 'Contract performance',
categories: {
dataSubjects: ['website visitors', 'registered users'],
personalData: ['name', 'email', 'password hash'],
recipients: ['email service provider'],
transfers: 'none'
},
retention: '3 years after account closure',
security: [
'Password hashing with bcrypt',
'HTTPS encryption',
'Access controls',
'Regular backups'
]
};
7. Third-Party Services
// GDPR-compliant analytics
// Google Analytics with anonymized IP
// Privacy-focused alternatives
// - Plausible Analytics (no cookies, EU-hosted)
// - Matomo (self-hosted option)
// - Fathom Analytics
// Email marketing compliance
class EmailMarketingService {
async subscribe(email, source) {
// Double opt-in process
const token = generateToken();
await PendingSubscription.create({
email,
token,
source,
timestamp: new Date()
});
await this.sendConfirmationEmail(email, token);
}
async confirmSubscription(token) {
const pending = await PendingSubscription.findOne({ token });
if (!pending) {
throw new Error('Invalid token');
}
await Subscription.create({
email: pending.email,
confirmedAt: new Date(),
source: pending.source,
ipAddress: pending.ipAddress
});
await PendingSubscription.deleteOne({ token });
}
async unsubscribe(email) {
await Subscription.deleteOne({ email });
// Add to suppression list
await SuppressionList.create({
email,
reason: 'user_request',
timestamp: new Date()
});
}
}
// Processor agreement checklist
const processorChecklist = [
'☐ Signed Data Processing Agreement',
'☐ GDPR compliance confirmed',
'☐ EU data hosting or Privacy Shield certified',
'☐ Sub-processors disclosed',
'☐ Security measures documented',
'☐ Breach notification procedures',
'☐ Data return/deletion process',
'☐ Audit rights established'
];
8. Best Practices
✓ GDPR Compliance Best Practices:
- ✓ Appoint a Data Protection Officer if required
- ✓ Conduct Data Protection Impact Assessments (DPIAs)
- ✓ Implement privacy by design and by default
- ✓ Document all processing activities (ROPA)
- ✓ Obtain clear consent for non-essential processing
- ✓ Enable easy exercise of user rights
- ✓ Implement data retention policies
- ✓ Encrypt sensitive personal data
- ✓ Have Data Processing Agreements with processors
- ✓ Prepare breach notification procedures
- ✓ Regular staff training on data protection
- ✓ Keep privacy policy updated and accessible
- ✓ Document legal basis for each processing activity
- ✓ Regular compliance audits
- ✓ Minimize data collection and retention
Conclusion
GDPR compliance protects user privacy and builds trust. Implement user rights APIs, consent management, data protection by design, and breach notification procedures. Document everything, minimize data collection, and regularly audit compliance. Privacy is not just legal compliance but good business practice.
💡 Pro Tip: Use a consent management platform (CMP) like OneTrust, Cookiebot, or Osano for handling cookie consent across your website. These platforms provide pre-built compliant cookie banners, consent tracking, and integration with popular analytics/marketing tools. They automatically scan your website for cookies and help maintain GDPR compliance as your tool stack evolves.