πŸ”²

Consent Widget

The DPDPA Shield consent widget is the user-facing component of your compliance setup. It presents consent notices, records decisions, and provides ongoing preference management - all in compliance with DPDPA 2023 Section 5 and 6.

4
Visual states
22
Languages
4
Positions

Widget states

The widget has four visual states. Understanding each helps you configure and test your integration.

Compact Banner

First visit

Shown on first visit or when no consent is stored. Displays purpose summary with Accept All, Reject All, and Manage Preferences buttons.

When: No consent record in localStorage

Manage Preferences

Full preference panel

Full purpose-by-purpose preference panel. Each consent-based purpose has an individual toggle. Non-consent purposes (Contract / Legal Obligation) are shown as non-toggleable.

When: User clicks Manage Preferences OR returning user clicks the persistent button

Rejection Confirmation

2.5 second auto-dismiss

Shown for 2.5 seconds after Reject All or saving all-off preferences. Confirms that non-essential processing has stopped before the widget closes.

When: Immediately after rejection

Persistent Privacy Button

Always visible after consent

Small 36px floating shield button that stays visible after the widget is dismissed. Allows users to manage or withdraw consent at any time. Tooltip: Manage or withdraw your consent.

When: After any consent decision is made


Widget positioning

Set position in DPDPAShield.init(). The widget and its persistent button both anchor to the same corner.

Click a position above to see its code snippet.

DPDPAShield.init({
  apiKey: 'dpdpa_live_xxx',
  position: 'bottom-right' // default
})

Consent record status values

Consent records are immutable. Each new user action creates a new ConsentRecord. The most recent record is the current state.

StatusMeaning
ACCEPTEDAll non-required purposes accepted.
REJECTEDAll non-required purposes rejected.
PARTIALMixed - some accepted, some rejected.

Note: WITHDRAWN is a database-level status set when a user withdraws via the Rights Portal. It is not returned in the onConsent callback. To react to withdrawals in your backend, subscribe to the consent.withdrawn webhook event.

A record can also be partially withdrawn

When a Data Principal withdraws only some purposes, withdrawnAt stays null - the record is not fully withdrawn - while withdrawnPurposes accumulates the revoked purpose IDs. Checking only isWithdrawn will show false and incorrectly imply full consent is still active - always check isPartiallyWithdrawn too. See Analytics API below for the full response shape.



Consent withdrawal

DPDPA Section 6(4) requires withdrawal to be as easy as giving consent. DPDPA Shield provides three withdrawal mechanisms:

1Widget

Persistent privacy button β†’ Manage Preferences β†’ red "βœ• Withdraw all consent" link

For: All users on your website

2Rights Portal

dpdpashield.in/rights/[slug] β†’ Withdraw Consent tab β†’ Enter email β†’ Confirm

For: Users who cannot find the widget

3Withdrawal URL

Set withdrawalUrl in your consent notice. The SDK renders a "Withdraw consent" link in the widget footer automatically.

For: Rule 3(c) compliance

Toggling preferences off is not the same as withdrawing

Turning off purpose toggles in Manage Preferences and clicking Save writes a new consent record with a REJECTED or PARTIAL outcome through the normal consent-recording path - it does not create a WithdrawalRecord and does not trigger the DPO email or ComplianceTask below. Only the explicit "Withdraw all consent" link and the Rights Portal / withdrawal-URL flows go through full withdrawal.

What happens when withdrawal is recorded

●ConsentRecord status updated to WITHDRAWN
●Confirmation email sent to data principal with reference ID
●Action-required email sent to DPO
●HIGH priority ComplianceTask created with 7-day deadline (DPDPA Section 8(7))
●WithdrawalRecord stored for immutable audit trail

DPDPA Rule 3 disclosures in the widget

Rule 3 requires the consent notice to include contact details and a complaint mechanism. Configure these in your published notice - the widget renders them automatically:

FieldWhat it does
contactEmailDPO email address shown in the widget footer below action buttons.
complaintTextGrievance mechanism text shown in the compact and preferences views.
withdrawalUrlLink rendered as 'Withdraw consent' in the widget footer. Points users to the Rights Portal withdrawal tab.
DPDPA Shield Dashboard β†’ Consent β†’ Notices β†’ Edit Notice
// Set these fields in the Notice Builder:
//   Contact Email:   privacy@yourdomain.com
//   Complaint Text:  "To raise a grievance, contact our DPO at privacy@yourdomain.com
//                    or write to: [postal address]. We will respond within 7 days."
//   Withdrawal URL:  https://dpdpashield.in/rights/your-slug?apiKey=dpdpa_live_xxx

// The SDK reads these from the /public-notice endpoint and renders them
// automatically - no code changes needed on your website.

Consent Analytics

Query consent metrics and records via API. All endpoints require Authorization: Bearer {token} from your dashboard session or a server API key.

GET/api/v1/consent/analytics

Returns consent metrics for the tenant: counts by status, purpose breakdown, language distribution, and withdrawal rate.

Auth
Bearer token
GET/api/v1/consent/records

Paginated list of all ConsentRecords for the tenant, including the notice version at the time of consent and the current notice version. Use the version comparison to identify stale consent records.

Query params
pagePage number (default: 1)
limitResults per page (default: 20)
statusFilter: active (withdrawnAt is null and not partially withdrawn) | partial (withdrawnPurposes set, withdrawnAt still null) | withdrawn (withdrawnAt is set)
Response shape
{
  items: ConsentRecord[],
  total: number,
  page: number,
  limit: number
}
GET/api/v1/consent/status/:hash

Check consent status for a specific Data Principal. Hash the user's email with SHA-256 (lowercase + trimmed) before calling. Returns an array - one entry per notice the principal has a consent record for, most recent first.

Path param
hashSHA-256 hex of lowercased + trimmed email
Response
{
  data: [{
    consentRecordId: string,
    noticeId: string,
    consentGiven: Record<string, boolean>,
    isWithdrawn: boolean,
    withdrawnAt: string | null,
    withdrawnPurposes: string[],
    isPartiallyWithdrawn: boolean,
    createdAt: string,
    proofHash: string
  }]
}
// empty array = no consent record for this principal

Need help integrating?

Our team responds within one business day.

Email hello@dpdpashield.in β†’