Usa este skill cuando desarrolles software que recolecte, almacene o procese información personal de usuarios. Aunque CCPA/CPRA es legislación de California, este skill se aplica como estándar de privacidad para cualquier software independientemente de la ubicación geográfica de los usuarios. Cubre derechos del consumidor (know, delete, correct, portability, opt-out), modelo de datos, opt-out DNSS con GPC, notice at collection, menores de edad, y checklist de cumplimiento.
Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Know which skills are safe — weekly.
SSkills DirectorySkills Directory
Is that skill safe to install?
Are you the author of Ccpa Cpra Es Skills Mauriciodelrio?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/thomasmoreai-ccpa-cpra-es-skills-mauriciodelrio)
---
name: ccpa-cpra-es-skills-mauriciodelrio
title: CCPA/CPRA — California Consumer Privacy Act & Privacy Rights Act
description: Usa este skill cuando desarrolles software que recolecte, almacene o procese información personal de usuarios. Aunque CCPA/CPRA es legislación de California, este skill se aplica como estándar de privacidad para cualquier software independientemente de la ubicación geográfica de los usuarios. Cubre derechos del consumidor (know, delete, correct, portability, opt-out), modelo de datos, opt-out DNSS con GPC, notice at collection, menores de edad, y checklist de cumplimiento.
author: mauriciodelrio
author_url: https://github.com/mauriciodelrio/delriodev-skills/tree/main/es-skills/governance-risk-and-compliance/ccpa-cpra
license: MIT
version: 0.1.0
execution_mode: open
jurisdiction: cross-jurisdiction
practice: regulatory
language: es
---
# CCPA/CPRA — California Consumer Privacy Act & Privacy Rights Act
CCPA (2020) y CPRA (2023) definen estándares de privacidad que deben aplicarse a cualquier software que maneje información personal, independientemente de la geografía de los usuarios. El modelo opera con opt-out (no requiere consentimiento previo para recolectar), tiene definición amplísima de "venta" de datos (incluye compartir para publicidad), y las penalidades originales son $2,500 por violación o $7,500 por violación intencional. La autoridad de referencia es la California Privacy Protection Agency (CPPA).
## Implementación
### 1. Modelo de Datos de Privacidad
```prisma
// prisma/schema.prisma
/// Registro de información personal recolectada por consumidor
model ConsumerPrivacyProfile {
id String @id @default(cuid())
// Identificador del consumidor (puede ser autenticado o no)
consumerEmail String?
accountId String? @unique
deviceId String?
// Preferencias de privacidad CCPA/CPRA
optOutSale Boolean @default(false) // "Do Not Sell My Personal Information"
optOutSharing Boolean @default(false) // "Do Not Share My Personal Information" (CPRA)
limitSensitiveUse Boolean @default(false) // Limitar uso de SPI (CPRA)
// Consentimiento financiero (opt-in para menores)
isMinor Boolean @default(false)
parentalConsent Boolean?
// Categorías de PI recolectada (para disclosure)
categoriesCollected String[] @default([])
sourcesOfCollection String[] @default([])
purposesOfUse String[] @default([])
categoriesShared String[] @default([])
// Tracking
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastVerified DateTime?
// Relaciones
requests ConsumerRequest[]
@@index([consumerEmail])
@@index([accountId])
@@map("consumer_privacy_profiles")
}
/// Solicitudes de consumidores (DSAR — Data Subject Access Requests)
model ConsumerRequest {
id String @id @default(cuid())
profileId String
profile ConsumerPrivacyProfile @relation(fields: [profileId], references: [id])
type ConsumerRequestType
status RequestStatus @default(RECEIVED)
// CCPA requiere responder en 45 días (extensible a 90)
receivedAt DateTime @default(now())
acknowledgedAt DateTime?
deadlineAt DateTime // 45 días desde recepción
extendedDeadline DateTime? // Extensión hasta 90 días
completedAt DateTime?
// Verificación de identidad (obligatorio antes de procesar)
identityVerified Boolean @default(false)
verificationMethod String?
// Respuesta
responseData Json?
denialReason String?
@@map("consumer_requests")
}
enum ConsumerRequestType {
RIGHT_TO_KNOW // Saber qué PI se recolecta y por qué
RIGHT_TO_DELETE // Eliminar toda la PI
RIGHT_TO_CORRECT // Corregir PI inexacta (CPRA)
RIGHT_TO_PORTABILITY // Obtener PI en formato portable (CPRA)
OPT_OUT_SALE // No vender mi PI
OPT_OUT_SHARING // No compartir mi PI para publicidad (CPRA)
LIMIT_SENSITIVE // Limitar uso de info sensible (CPRA)
}
enum RequestStatus {
RECEIVED
IDENTITY_VERIFICATION
IN_PROGRESS
COMPLETED
DENIED
EXTENDED
}
```
---
### 2. Servicio de Derechos del Consumidor
```typescript
// services/ccpa-consumer-rights.service.ts
import { PrismaClient, ConsumerRequestType, RequestStatus } from '@prisma/client';
import pino from 'pino';
const prisma = new PrismaClient();
const logger = pino({ name: 'ccpa-rights' });
// CCPA: El consumidor puede hacer solicitudes 2 veces en un período de 12 meses
const MAX_REQUESTS_PER_YEAR = 2;
const RESPONSE_DEADLINE_DAYS = 45;
const MAX_EXTENSION_DAYS = 90;
export class CCPAConsumerRightsService {
/**
* Iniciar una solicitud de consumidor.
* CCPA §1798.100-§1798.135
*/
async submitRequest(
consumerIdentifier: { email?: string; accountId?: string },
requestType: ConsumerRequestType,
) {
// Buscar o crear perfil de privacidad
const profile = await this.findOrCreateProfile(consumerIdentifier);
// Verificar límite de solicitudes (2 por 12 meses para RIGHT_TO_KNOW)
if (requestType === 'RIGHT_TO_KNOW') {
const recentRequests = await prisma.consumerRequest.count({
where: {
profileId: profile.id,
type: 'RIGHT_TO_KNOW',
receivedAt: {
gte: new Date(Date.now() - 365 * 24 * 60 * 60 * 1000),
},
},
});
if (recentRequests >= MAX_REQUESTS_PER_YEAR) {
return {
success: false,
error: 'Has alcanzado el límite de 2 solicitudes de conocimiento por período de 12 meses.',
};
}
}
const deadline = new Date();
deadline.setDate(deadline.getDate() + RESPONSE_DEADLINE_DAYS);
const request = await prisma.consumerRequest.create({
data: {
profileId: profile.id,
type: requestType,
status: 'IDENTITY_VERIFICATION',
deadlineAt: deadline,
},
});
logger.info({
event: 'consumer_request_submitted',
requestId: request.id,
type: requestType,
deadline: deadline.toISOString(),
}, 'Solicitud de consumidor CCPA recibida');
// Enviar email de confirmación (CCPA requiere acusar recibo en 10 días)
// await this.sendAcknowledgment(profile, request);
return {
success: true,
requestId: request.id,
type: requestType,
status: 'IDENTITY_VERIFICATION',
deadline: deadline.toISOString(),
message: 'Solicitud recibida. Debes verificar tu identidad para continuar.',
};
}
/**
* Derecho a Saber (Right to Know).
* CCPA §1798.100, §1798.110, §1798.115
*
* El consumidor tiene derecho a saber:
* - Qué categorías de PI se recolectan
* - Las fuentes de recolección
* - El propósito comercial de la recolección
* - Las categorías de terceros con quienes se comparte
* - Las piezas específicas de PI recolectada
*/
async processRightToKnow(requestId: string): Promise<object> {
const request = await this.getVerifiedRequest(requestId, 'RIGHT_TO_KNOW');
const profile = await prisma.consumerPrivacyProfile.findUniqueOrThrow({
where: { id: request.profileId },
});
// Recopilar toda la información personal del consumidor
const personalInfo = await this.collectPersonalInfo(profile.accountId!);
const disclosure = {
// §1798.110(a)(1): Categorías de PI recolectada
categoriesCollected: [
'Identificadores (email, nombre)',
'Actividad en internet (historial de uso)',
'Información comercial (transacciones)',
'Geolocalización (si se proporcionó)',
],
// §1798.110(a)(2): Categorías de fuentes
sourcesOfCollection: [
'Directamente del consumidor',
'Automáticamente mediante cookies y tecnologías similares',
],
// §1798.110(a)(3): Propósito comercial
businessPurposes: [
'Proveer el servicio solicitado',
'Mantener la seguridad de la cuenta',
'Mejorar el servicio',
'Cumplir con obligaciones legales',
],
// §1798.110(a)(4): Categorías de terceros
thirdPartyCategories: [
'Proveedores de servicios (hosting, email)',
'Procesadores de pagos',
],
// §1798.110(a)(5): Piezas específicas de PI
specificPersonalInfo: personalInfo,
// §1798.115: Información sobre venta/compartición
salesAndSharing: {
sold: false,
shared: false,
categoriesSold: [],
categoriesShared: [],
},
};
await prisma.consumerRequest.update({
where: { id: requestId },
data: {
status: 'COMPLETED',
completedAt: new Date(),
responseData: disclosure as any,
},
});
logger.info({
event: 'right_to_know_completed',
requestId,
profileId: profile.id,
}, 'Right to Know procesado');
return disclosure;
}
/**
* Derecho a Eliminar (Right to Delete).
* CCPA §1798.105
*
* Excepciones permitidas (no necesitas eliminar si):
* - Necesario para completar la transacción
* - Seguridad/detección de fraude
* - Debugging
* - Cumplimiento legal
*/
async processRightToDelete(requestId: string): Promise<{ success: boolean; deletedCategories: string[] }> {
const request = await this.getVerifiedRequest(requestId, 'RIGHT_TO_DELETE');
const profile = await prisma.consumerPrivacyProfile.findUniqueOrThrow({
where: { id: request.profileId },
});
const deletedCategories: string[] = [];
await prisma.$transaction(async (tx) => {
if (profile.accountId) {
// Pseudonimizar datos de usuario
await tx.user.update({
where: { id: profile.accountId },
data: {
name: '[ELIMINADO]',
email: `deleted_${Date.now()}@deleted.invalid`,
phone: null,
address: null,
deletedAt: new Date(),
},
});
deletedCategories.push('Identificadores personales');
// Eliminar historial de actividad
// await tx.activityLog.deleteMany({ where: { userId: profile.accountId } });
deletedCategories.push('Actividad en internet');
}
});
await prisma.consumerRequest.update({
where: { id: requestId },
data: {
status: 'COMPLETED',
completedAt: new Date(),
responseData: { deletedCategories } as any,
},
});
// CCPA requiere notificar a service providers para que también eliminen
// await this.notifyServiceProviders(profile.accountId, 'delete');
logger.info({
event: 'right_to_delete_completed',
requestId,
deletedCategories,
}, 'Right to Delete procesado');
return { success: true, deletedCategories };
}
/**
* Derecho a Corregir (Right to Correct) — CPRA §1798.106
*/
async processRightToCorrect(
requestId: string,
corrections: Record<string, unknown>,
): Promise<{ success: boolean; correctedFields: string[] }> {
const request = await this.getVerifiedRequest(requestId, 'RIGHT_TO_CORRECT');
const correctedFields = Object.keys(corrections);
// Validar que solo se corrijan campos permitidos
const allowedFields = ['name', 'email', 'phone', 'address'];
const invalidFields = correctedFields.filter(f => !allowedFields.includes(f));
if (invalidFields.length > 0) {
throw new Error(`Campos no permitidos para corrección: ${invalidFields.join(', ')}`);
}
const profile = await prisma.consumerPrivacyProfile.findUniqueOrThrow({
where: { id: request.profileId },
});
if (profile.accountId) {
await prisma.user.update({
where: { id: profile.accountId },
data: corrections as any,
});
}
await prisma.consumerRequest.update({
where: { id: requestId },
data: {
status: 'COMPLETED',
completedAt: new Date(),
responseData: { correctedFields } as any,
},
});
logger.info({
event: 'right_to_correct_completed',
requestId,
correctedFields,
}, 'Right to Correct procesado');
return { success: true, correctedFields };
}
// --- Helpers privados ---
private async findOrCreateProfile(identifier: { email?: string; accountId?: string }) {
const where = identifier.accountId
? { accountId: identifier.accountId }
: { consumerEmail: identifier.email };
let profile = await prisma.consumerPrivacyProfile.findFirst({ where });
if (!profile) {
profile = await prisma.consumerPrivacyProfile.create({
data: {
consumerEmail: identifier.email,
accountId: identifier.accountId,
},
});
}
return profile;
}
private async getVerifiedRequest(requestId: string, expectedType: ConsumerRequestType) {
const request = await prisma.consumerRequest.findUniqueOrThrow({
where: { id: requestId },
});
if (request.type !== expectedType) {
throw new Error(`Tipo de solicitud incorrecto: esperado ${expectedType}, recibido ${request.type}`);
}
if (!request.identityVerified) {
throw new Error('La identidad del consumidor no ha sido verificada');
}
return request;
}
private async collectPersonalInfo(accountId: string): Promise<Record<string, unknown>> {
const user = await prisma.user.findUnique({
where: { id: accountId },
select: {
name: true,
email: true,
createdAt: true,
},
});
return {
profile: user,
// Agregar más fuentes de datos según tu aplicación
};
}
}
```
---
### 3. Opt-Out "Do Not Sell or Share" (DNSS)
```typescript
// middleware/ccpa-opt-out.middleware.ts
import { Request, Response, NextFunction } from 'express';
import { PrismaClient } from '@prisma/client';
import pino from 'pino';
const prisma = new PrismaClient();
const logger = pino({ name: 'ccpa-opt-out' });
/**
* CCPA §1798.120: Derecho a Opt-Out de la venta de PI.
* CPRA §1798.120: Extendido a "venta O compartición" de PI.
*
* REQUISITOS:
* 1. Link visible "Do Not Sell or Share My Personal Information" en el sitio
* 2. Respetar Global Privacy Control (GPC) header
* 3. No pedir login para ejercer el opt-out
* 4. No volver a pedir consentimiento por 12 meses mínimo
*/
/**
* Detectar señal de Global Privacy Control (GPC).
* Los navegadores pueden enviar esta señal automáticamente.
* CCPA/CPRA OBLIGAN a respetar GPC como opt-out válido.
*/
export function detectGlobalPrivacyControl(req: Request, _res: Response, next: NextFunction) {
// GPC viene como header Sec-GPC: 1
const gpcHeader = req.headers['sec-gpc'];
if (gpcHeader === '1') {
// Tratar como opt-out de venta Y compartición
res.locals.gpcEnabled = true;
logger.info({
event: 'gpc_detected',
ip: req.ip,
userAgent: req.headers['user-agent'],
}, 'Global Privacy Control detectado — respetando opt-out automático');
}
next();
}
/**
* Middleware para verificar opt-out antes de compartir datos con terceros.
* USAR en cualquier endpoint que envíe datos a analytics, ad networks, etc.
*/
export function checkOptOutBeforeSharing(req: Request, res: Response, next: NextFunction) {
const isOptedOut = res.locals.gpcEnabled || res.locals.consumerOptedOut;
if (isOptedOut) {
// No enviar datos a partners de advertising/analytics
res.locals.allowThirdPartySharing = false;
res.locals.allowTargetedAds = false;
res.locals.allowCrossSiteTracking = false;
} else {
res.locals.allowThirdPartySharing = true;
res.locals.allowTargetedAds = true;
res.locals.allowCrossSiteTracking = true;
}
next();
}
/**
* API de Opt-Out.
* No requiere autenticación — cualquier consumidor puede ejercer este derecho.
*/
export async function handleOptOut(req: Request, res: Response) {
const { email, optOutSale, optOutSharing, limitSensitiveUse } = req.body;
// Buscar o crear perfil
let profile = await prisma.consumerPrivacyProfile.findFirst({
where: { consumerEmail: email },
});
if (profile) {
profile = await prisma.consumerPrivacyProfile.update({
where: { id: profile.id },
data: {
optOutSale: optOutSale ?? profile.optOutSale,
optOutSharing: optOutSharing ?? profile.optOutSharing,
limitSensitiveUse: limitSensitiveUse ?? profile.limitSensitiveUse,
lastVerified: new Date(),
},
});
} else {
profile = await prisma.consumerPrivacyProfile.create({
data: {
consumerEmail: email,
optOutSale: optOutSale ?? false,
optOutSharing: optOutSharing ?? false,
limitSensitiveUse: limitSensitiveUse ?? false,
},
});
}
logger.info({
event: 'opt_out_updated',
profileId: profile.id,
optOutSale: profile.optOutSale,
optOutSharing: profile.optOutSharing,
limitSensitiveUse: profile.limitSensitiveUse,
}, 'Preferencias de opt-out actualizadas');
res.json({
success: true,
preferences: {
optOutSale: profile.optOutSale,
optOutSharing: profile.optOutSharing,
limitSensitiveUse: profile.limitSensitiveUse,
},
message: 'Tus preferencias de privacidad han sido actualizadas.',
});
}
```
---
### 4. Notice at Collection (Aviso en Punto de Recolección)
```typescript
// config/ccpa-notice.config.ts
/**
* CCPA §1798.100(b): Aviso al consumidor en el punto de recolección.
* Debe informar ANTES de recolectar datos:
* - Qué categorías se recolectan
* - Para qué propósitos
* - Si se venden o comparten
* - Período de retención
*/
export interface NoticeAtCollection {
categories: CategoryNotice[];
retentionPolicies: RetentionPolicy[];
thirdPartyDisclosure: ThirdPartyDisclosure[];
links: { privacyPolicy: string; doNotSell: string; rights: string };
}
interface CategoryNotice {
category: string;
examples: string[];
purpose: string;
retentionPeriod: string;
sold: boolean;
shared: boolean;
}
interface RetentionPolicy {
dataType: string;
retentionPeriod: string;
justification: string;
}
interface ThirdPartyDisclosure {
recipientCategory: string;
purpose: string;
dataCategories: string[];
}
export const NOTICE_AT_COLLECTION: NoticeAtCollection = {
categories: [
{
category: 'Identificadores',
examples: ['Nombre', 'Email', 'Dirección IP'],
purpose: 'Proveer el servicio, comunicaciones',
retentionPeriod: 'Mientras la cuenta esté activa + 30 días',
sold: false,
shared: false,
},
{
category: 'Información comercial',
examples: ['Historial de compras', 'Suscripciones'],
purpose: 'Proveer el servicio, facturación',
retentionPeriod: '7 años (requisitos fiscales)',
sold: false,
shared: false,
},
{
category: 'Actividad en Internet',
examples: ['Páginas visitadas', 'Funcionalidades usadas'],
purpose: 'Mejorar el servicio, analytics',
retentionPeriod: '12 meses',
sold: false,
shared: false,
},
],
retentionPolicies: [
{
dataType: 'Datos de cuenta',
retentionPeriod: 'Duración de cuenta + 30 días de gracia',
justification: 'Necesario para proveer el servicio',
},
{
dataType: 'Registros de transacciones',
retentionPeriod: '7 años',
justification: 'Requisitos fiscales y legales',
},
{
dataType: 'Logs de actividad',
retentionPeriod: '12 meses',
justification: 'Seguridad y mejora del servicio',
},
],
thirdPartyDisclosure: [
{
recipientCategory: 'Proveedores de servicios (Service Providers)',
purpose: 'Hosting, email, procesamiento de pagos',
dataCategories: ['Identificadores', 'Información comercial'],
},
],
links: {
privacyPolicy: '/privacy',
doNotSell: '/do-not-sell',
rights: '/privacy-rights',
},
};
/**
* Endpoint para servir el notice at collection y links de privacidad.
*/
export function getPrivacyNotice(): NoticeAtCollection {
return NOTICE_AT_COLLECTION;
}
```
---
### 5. Menores de Edad (CCPA §1798.120(c-d))
```typescript
// services/ccpa-minors.service.ts
import { PrismaClient } from '@prisma/client';
import pino from 'pino';
const prisma = new PrismaClient();
const logger = pino({ name: 'ccpa-minors' });
/**
* CCPA trata a los menores de forma especial:
* - Menores de 13 años: Requieren consentimiento PARENTAL (opt-in) para vender/compartir PI
* - 13-15 años: Requieren consentimiento del MENOR (opt-in) para vender/compartir PI
* - 16+ años: Se aplican las reglas normales (opt-out)
*
* CPRA extiende esto a COMPARTIR datos, no solo vender.
*/
export class CCPAMinorsService {
/**
* Verificar si podemos vender/compartir datos de un consumidor menor.
*/
async canSellOrShareData(consumerId: string): Promise<{
allowed: boolean;
reason: string;
}> {
const profile = await prisma.consumerPrivacyProfile.findFirst({
where: { accountId: consumerId },
});
if (!profile) {
return { allowed: false, reason: 'Perfil de privacidad no encontrado' };
}
// Si el consumidor ha hecho opt-out (cualquier edad > 16)
if (profile.optOutSale || profile.optOutSharing) {
return { allowed: false, reason: 'Consumidor ejerció opt-out' };
}
// Verificación de menores
if (profile.isMinor) {
if (!profile.parentalConsent) {
return {
allowed: false,
reason: 'Menor de edad — se requiere consentimiento parental verificado',
};
}
}
return { allowed: true, reason: 'Permitido' };
}
}
```
---
## Flujo de trabajo del agente
1. Identificar si la aplicación recolecta PI de residentes de California y si cumple los umbrales de aplicabilidad ($25M ingresos, 100k+ consumidores, o 50%+ ingresos por venta de datos).
2. Implementar el modelo de datos de privacidad con perfiles de consumidor y solicitudes DSAR.
3. Implementar el servicio de derechos del consumidor cubriendo todos los derechos aplicables (know, delete, correct, portability, opt-out sale, opt-out sharing, limit SPI).
4. Agregar middleware de opt-out con detección de Global Privacy Control (GPC) y verificación antes de compartir datos con terceros.
5. Configurar el Notice at Collection con categorías de PI, propósitos, políticas de retención y links obligatorios.
6. Implementar protección de menores con opt-in verificado para menores de 16 años.
7. Validar contra el checklist de cumplimiento antes de desplegar.
## Gotchas
El opt-out de venta/compartición NO debe requerir login ni autenticación — cualquier consumidor puede ejercerlo. La señal GPC (`Sec-GPC: 1`) es legalmente vinculante bajo CCPA/CPRA y debe respetarse como opt-out automático. Las solicitudes de consumidor deben acusarse en 10 días hábiles y resolverse en 45 días (extensible a 90 con notificación). El consumidor puede hacer máximo 2 solicitudes Right to Know por período de 12 meses. No discriminar al consumidor por ejercer sus derechos (no cobrar más ni degradar servicio). Los menores de 13 requieren consentimiento parental, y los de 13-15 requieren consentimiento del propio menor (opt-in) antes de vender o compartir su PI. Mantener registro de todas las solicitudes por 24 meses. Los contratos con service providers deben incluir cláusulas que prohíban uso de PI fuera del servicio contratado. Evitar dark patterns en el proceso de opt-out.
---
## Checklist de Cumplimiento CCPA/CPRA
### Derechos del Consumidor
- [ ] Right to Know (saber qué PI se recolecta y cómo se usa)
- [ ] Right to Delete (eliminar PI)
- [ ] Right to Correct (corregir PI inexacta) — CPRA
- [ ] Right to Portability (obtener PI en formato portable) — CPRA
- [ ] Right to Opt-Out de venta de PI
- [ ] Right to Opt-Out de compartición de PI — CPRA
- [ ] Right to Limit uso de Sensitive Personal Information — CPRA
- [ ] Right to Non-Discrimination
### Avisos y Links
- [ ] Privacy Policy actualizada con disclosures CCPA/CPRA
- [ ] Notice at Collection (antes de recolectar datos)
- [ ] Link "Do Not Sell or Share My Personal Information" visible
- [ ] Link "Limit the Use of My Sensitive Personal Information" — CPRA
- [ ] Información sobre retención de datos
### Operaciones
- [ ] Verificación de identidad para solicitudes de consumidores
- [ ] Proceso de respuesta dentro de 45 días (máximo 90 con extensión)
- [ ] Acuse de recibo dentro de 10 días hábiles
- [ ] Registro de solicitudes por 24 meses
- [ ] Global Privacy Control (GPC) respetado
- [ ] Protección especial para menores de 16 años
- [ ] Contratos con service providers con cláusulas de privacidad
- [ ] Entrenamiento de empleados que manejan solicitudes de consumidores
---
## Referencias y Recursos
- [CCPA Texto completo — California Legislative Information](https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml?division=3.&part=4.&lawCode=CIV&title=1.81.5)
- [CPRA Texto completo](https://thecpra.org/)
- [California Privacy Protection Agency (CPPA)](https://cppa.ca.gov/)
- [Global Privacy Control (GPC)](https://globalprivacycontrol.org/)
- [CCPA Regulations — Final Text](https://www.oag.ca.gov/privacy/ccpa/regs)