DPDPA Cookie Compliance Guide
India's Digital Personal Data Protection Act (DPDPA), 2023 requires opt-in consent before non-essential cookies run for Indian visitors — but it also asks for a few things GDPR banners typically skip, as covered in GDPR vs DPDPA. This is the implementation checklist, not the statute text.
What a DPDPA-compliant cookie banner needs
- Opt-in by default.Every non-essential cookie category starts denied. No pre-checked boxes, no “continuing to browse implies consent”.
- Data Fiduciary name, in the notice. DPDPA expects the entity collecting data to identify itself directly in the consent notice, not just buried in a privacy policy link.
- Grievance officer contact. A name or contact channel for complaints, shown alongside or one click from the notice.
- An age gate at 18, not 16.DPDPA's parental-consent threshold is higher than most GDPR-adjacent laws — a banner tuned for Europe will often use the wrong cutoff for India.
- No reliance on GPC.DPDPA doesn't reference Global Privacy Control, so a banner can't treat the browser signal as consent or as an opt-out for Indian traffic the way it might for CCPA states.
- A durable consent record. Timestamp, what was agreed to, and the ability to withdraw just as easily as it was given.
Example — an opt-in-dpdpa profile
Rather than writing this notice logic from scratch, you can route India-mapped traffic to a dedicated compliance profile. Here's what that looks like configured through Consenti, an open-source consent widget with a built-in opt-in-dpdpa profile — shown as one concrete implementation, not the only way to do this:
import { ConsentiSetup } from '@consenti/ui'
new ConsentiSetup({
compliance: { type: 'opt-in-dpdpa' }, // fiduciary name + grievance officer + 18+ age gate
utils: {
geo: { autoDetect: true }, // route India traffic here automatically
},
})The opt-in-dpdpa group ships with the fiduciary-name and grievance-officer fields as first-class config, sets the age gate to 18, and ignores GPC by design — so the notice matches the statute without extra copywriting per deployment.
Recording the consent decision
Whatever banner you use, the record you keep should answer: what was shown, what was chosen, when, and by which policy version. If you're also running a backend, an immutable audit log (append-only, never edited or deleted) is the safest way to keep that trail defensible.
import { createConsenti } from '@consenti/api'
const consenti = createConsenti({
storage: { driver: 'sqlite' }, // or postgres/mysql/mongo at scale
compliance: { type: 'opt-in-dpdpa' },
})
// every decision is written to an append-only audit_logs table