CCPA Technical Implementation Requirements
CCPA Technical Implementation Requirements
CCPA introduces different requirements focusing on transparency and consumer control over data sales. The concept of "selling" personal information extends beyond monetary transactions to include valuable consideration, requiring careful tracking of data flows to third parties. Technical implementations must support consumer rights to know what information is collected, delete personal information, opt-out of sales, and non-discrimination for exercising rights.
The "Do Not Sell My Personal Information" requirement necessitates prominent opt-out mechanisms and technical controls to prevent data sharing with third parties. Unlike GDPR's opt-in consent model, CCPA allows opt-out approaches, but systems must respect consumer choices immediately and comprehensively. This includes updating all systems that might share data and notifying third parties of opt-out requests.
// Example: CCPA compliance implementation for web applications
class CCPAComplianceManager {
constructor(config) {
this.config = config;
this.dataInventory = new DataInventory();
this.thirdPartyManager = new ThirdPartyManager();
this.auditLogger = new AuditLogger();
}
async initializeCCPACompliance() {
// Set up required endpoints
this.setupPrivacyRightsEndpoints();
// Initialize cookie consent with CCPA mode
this.initializeCookieConsent();
// Set up data flow monitoring
await this.setupDataFlowMonitoring();
// Configure third-party integrations
await this.configureThirdPartyIntegrations();
}
setupPrivacyRightsEndpoints() {
// POST /api/privacy/ccpa/access-request
app.post('/api/privacy/ccpa/access-request', async (req, res) => {
try {
const result = await this.handleAccessRequest(req.body);
res.json(result);
} catch (error) {
this.handleError(res, error);
}
});
// POST /api/privacy/ccpa/deletion-request
app.post('/api/privacy/ccpa/deletion-request', async (req, res) => {
try {
const result = await this.handleDeletionRequest(req.body);
res.json(result);
} catch (error) {
this.handleError(res, error);
}
});
// POST /api/privacy/ccpa/opt-out
app.post('/api/privacy/ccpa/opt-out', async (req, res) => {
try {
// CCPA doesn't require verification for opt-out
const result = await this.handleOptOut(req);
res.json(result);
} catch (error) {
this.handleError(res, error);
}
});
// GET /api/privacy/ccpa/do-not-sell-status
app.get('/api/privacy/ccpa/do-not-sell-status', async (req, res) => {
const status = await this.getDoNotSellStatus(req);
res.json({ optedOut: status });
});
}
async handleOptOut(request) {
// Extract identifier (could be cookie, device ID, etc.)
const identifier = this.extractIdentifier(request);
// Record opt-out without requiring account
const optOutRecord = {
id: generateId(),
identifier: identifier,
timestamp: new Date().toISOString(),
ipAddress: hashIP(request.ip),
userAgent: request.headers['user-agent'],
method: 'web_form'
};
// Store opt-out preference
await this.storeOptOut(optOutRecord);
// Update all systems immediately
await this.propagateOptOut(identifier);
// Set opt-out cookie
this.setOptOutCookie(request.res);
// Notify third parties
await this.notifyThirdPartiesOfOptOut(identifier);
// Audit log
await this.auditLogger.log({
event: 'ccpa_opt_out',
identifier: hashIdentifier(identifier),
timestamp: optOutRecord.timestamp
});
return {
success: true,
message: 'You have been opted out of the sale of personal information'
};
}
async propagateOptOut(identifier) {
// Update analytics to exclude user
await this.updateAnalyticsOptOut(identifier);
// Update advertising systems
await this.updateAdvertisingOptOut(identifier);
// Update data warehouse
await this.updateDataWarehouseOptOut(identifier);
// Update real-time bidding
await this.disableRTBForUser(identifier);
}
async notifyThirdPartiesOfOptOut(identifier) {
const thirdParties = await this.thirdPartyManager.getDataRecipients();
const notifications = thirdParties.map(async (party) => {
try {
if (party.supportsAutomatedOptOut) {
await this.sendAutomatedOptOut(party, identifier);
} else {
await this.queueManualNotification(party, identifier);
}
return { party: party.name, status: 'notified' };
} catch (error) {
console.error(`Failed to notify ${party.name}:`, error);
return { party: party.name, status: 'failed', error: error.message };
}
});
return await Promise.all(notifications);
}
async handleAccessRequest(requestData) {
// Verify identity (CCPA requires reasonable verification)
const verified = await this.verifyIdentity(requestData);
if (!verified) {
throw new Error('Identity verification failed');
}
const { consumerId } = verified;
// Gather all personal information
const personalInfo = await this.gatherPersonalInformation(consumerId);
// Categories of information collected
const categories = this.categorizeInformation(personalInfo);
// Sources of information
const sources = await this.getInformationSources(consumerId);
// Business purposes for collection
const purposes = this.getBusinessPurposes(categories);
// Third parties with whom info is shared
const thirdParties = await this.getThirdPartySharing(consumerId);
// Specific pieces of information
const specificInfo = this.formatSpecificInformation(personalInfo);
const report = {
requestId: generateId(),
generatedAt: new Date().toISOString(),
coveringPeriod: '12 months',
categories: categories,
sources: sources,
purposes: purposes,
thirdPartySharing: thirdParties,
specificInformation: specificInfo,
saleOfInformation: await this.getInfoSaleDetails(consumerId)
};
// Log access request
await this.auditLogger.log({
event: 'ccpa_access_request',
consumerId: hashId(consumerId),
timestamp: report.generatedAt
});
return report;
}
async handleDeletionRequest(requestData) {
// Verify identity
const verified = await this.verifyIdentity(requestData);
if (!verified) {
throw new Error('Identity verification failed');
}
const { consumerId } = verified;
// Check for exceptions
const exceptions = await this.checkDeletionExceptions(consumerId);
const deletionReport = {
requestId: generateId(),
consumerId: consumerId,
timestamp: new Date().toISOString(),
deleted: [],
retained: []
};
// Get all data categories
const dataCategories = await this.dataInventory.getConsumerDataCategories(consumerId);
for (const category of dataCategories) {
if (exceptions.includes(category)) {
deletionReport.retained.push({
category: category,
reason: this.getExceptionReason(category)
});
} else {
// Delete data in this category
await this.deleteDataCategory(consumerId, category);
deletionReport.deleted.push(category);
}
}
// Notify third parties of deletion
await this.notifyThirdPartiesOfDeletion(consumerId);
// Log deletion
await this.auditLogger.log({
event: 'ccpa_deletion_request',
consumerId: hashId(consumerId),
timestamp: deletionReport.timestamp,
categoriesDeleted: deletionReport.deleted.length
});
return deletionReport;
}
checkDeletionExceptions(consumerId) {
// CCPA exceptions to deletion
const exceptions = [];
// Complete transaction exception
if (await this.hasIncompleteTransactions(consumerId)) {
exceptions.push('transaction_data');
}
// Security/fraud prevention exception
exceptions.push('security_logs');
// Legal compliance exception
if (await this.hasLegalObligations(consumerId)) {
exceptions.push('compliance_records');
}
// Internal uses exception (compatible with expectations)
exceptions.push('internal_analytics');
return exceptions;
}
initializeCookieConsent() {
// CCPA-specific cookie consent
window.CCPAConsent = {
init: () => {
// Check for Global Privacy Control
if (navigator.globalPrivacyControl) {
this.handleOptOut({ automated: true, source: 'GPC' });
}
// Show opt-out notice for California residents
if (this.isCaliforniaResident()) {
this.showOptOutNotice();
}
},
showOptOutNotice: () => {
const notice = document.createElement('div');
notice.className = 'ccpa-notice';
notice.innerHTML = `
<p>California residents: We may sell your personal information.</p>
<a href="/privacy/do-not-sell" class="do-not-sell-link">
Do Not Sell My Personal Information
</a>
<button onclick="CCPAConsent.dismiss()">Dismiss</button>
`;
document.body.appendChild(notice);
}
};
}
}