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);
            }
        };
    }
}