📦

JavaScript SDK

Embed DPDPA-compliant consent management on any website in minutes. The SDK handles widget rendering, consent recording, multilingual support, and proof storage automatically.

22
Indian languages supported
~10 KB
gzipped bundle size

Installation

index.html
<script src="https://api.dpdpashield.in/sdk/dpdpashield-sdk.js"></script>

Add this tag before your closing </body>. The SDK exposes a global DPDPAShield object.


Quick Start

Minimal working integration for the two most common setups.

Next.js App Router

app/layout.tsx
import Script from 'next/script'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        <Script
          src="https://api.dpdpashield.in/sdk/dpdpashield-sdk.js"
          strategy="afterInteractive"
        />
        <Script
          id="dpdpa-init"
          strategy="afterInteractive"
          dangerouslySetInnerHTML={{ __html: `
            (function() {
              function init() {
                if (typeof DPDPAShield === 'undefined') {
                  setTimeout(init, 100);
                  return;
                }
                DPDPAShield.init({
                  apiKey: '${process.env.NEXT_PUBLIC_DPDPA_API_KEY}'
                });
              }
              init();
            })();
          `}}
        />
      </body>
    </html>
  )
}

Plain HTML

index.html
<!DOCTYPE html>
<html>
<body>
  <!-- your content -->

  <script src="https://api.dpdpashield.in/sdk/dpdpashield-sdk.js"></script>
  <script>
    DPDPAShield.init({
      apiKey: 'dpdpa_live_YOUR_KEY_HERE'
    });
  </script>
</body>
</html>

Your API key is in Settings → API Keys. Keys starting with dpdpa_live_ are safe to embed publicly - they only allow consent recording, not account access.


Configuration Reference

DPDPAShield.init(config)
ParameterTypeRequiredDescription
apiKeystringRequiredYour tenant SDK key from Settings → API Keys. Starts with dpdpa_live_.
layoutstringOptional'modal' - a dialog centered on a dimmed backdrop, showing every purpose with its consent duration and data categories up front, a Rights summary, and A-/A/A+ text-size controls. 'compact' - the smaller card anchored to a screen corner (position below applies), with purposes behind a separate Manage Preferences step. Set to 'compact' to opt out of the default.Default: modal
positionstringOptionalWidget anchor position. One of: bottom-right | bottom-left | bottom-center | top-center. Only used when layout is 'compact' - ignored by the default centered modal.Default: bottom-right
showBadgebooleanOptionalShow a persistent 36px shield button after the widget is dismissed. Users can click it to re-open the widget at any time.Default: true
demobooleanOptionalDemo mode - loads a sample notice without making API calls. Useful for testing widget layout before your notice is configured.Default: false
onConsentfunctionOptionalCallback fired on every consent action. Called twice: once optimistically and once after API confirmation. See the onConsent section below.
noticeIdstringOptionalUUID of the specific consent notice to display. Required when you have multiple published notices (e.g. one per product/website). Find this on Consent → Notices - click the copy icon next to any notice. Defaults to your most recently published notice when omitted.
identifierHashstringOptionalPre-computed SHA-256 hex hash of the logged-in user's identifier (email/phone/userId), produced by your backend server. When provided, consent is attributed to this hash instead of the visitor's IP address. Must be exactly 64 lowercase hex characters. See Consent Attribution below.
externalIdstringOptionalYour own internal ID for this data principal (e.g. your users table primary key) - never derived by us, purely what you already know about your own logged-in user. Stored on the consent record so you can correlate it back to your own database later, without re-hashing lookups. Independent of identifierHash - set one, both, or neither. See Correlating Consent below.


The onConsent callback

Called twice on every consent action - immediately (optimistic, before the API responds) and again after the API confirms the record. Use the second call for any server-side logic since only it has a consentRecordId.

DPDPAShield.init({
  apiKey: 'dpdpa_live_xxx',
  onConsent: function(result) {
    // First call: result.consentRecordId is undefined
    // Second call: consentRecordId is the confirmed UUID
    console.log(result.status);
    // 'ACCEPTED' | 'REJECTED' | 'PARTIAL'

    console.log(result.consents);
    // { [purposeId]: boolean }
    // e.g. { 'purp_abc': true, 'purp_def': false }

    console.log(result.language);
    // 'EN' | 'HI' | 'TA' | ...

    console.log(result.consentRecordId);
    // UUID string - only set on second (confirmed) call
  }
});

Status values

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


Suppressing the widget on specific pages

Authentication and checkout pages often have their own consent flows. Suppress the widget on those paths with a path-check before calling init().

(function() {
  var skipPaths = [
    '/auth/sign-up',
    '/auth/login',
    '/auth/verify-email',
    '/checkout',
    '/order-confirmation',
  ];

  var currentPath = window.location.pathname;
  var shouldSkip = skipPaths.some(function(p) {
    return currentPath.startsWith(p);
  });

  if (shouldSkip) return;

  DPDPAShield.init({
    apiKey: 'dpdpa_live_YOUR_KEY_HERE'
  });
})();

22 Indian languages

The widget automatically renders in the user's language when a translation exists. A built-in language switcher lets users override at any time. Add translations in Consent → Notices → Manage Translations.

ENEnglish
HIHindi (हिन्दी)
TATamil (தமிழ்)
BNBengali (বাংলা)
TETelugu (తెలుగు)
MRMarathi (मराठी)
GUGujarati (ગુજરાતી)
KAKannada (ಕನ್ನಡ)
MLMalayalam (മലയാളം)
PAPunjabi (ਪੰਜਾਬੀ)
OROdia (ଓଡ଼ିଆ)
ASAssamese (অসমীয়া)
URUrdu (اردو)
KOKonkani (कोंकणी)
SASanskrit (संस्कृतम्)
SYSindhi (سنڌي)
NSONepali (नेपाली)
BODBodo (བོད་)
SITSanthali (ᱥᱟᱱᱛᱟᱲᱤ)
MAIMaithili (मैथिली)
DOGDogri (डोगरी)

The SDK falls back to English if a translation is unavailable for the user's language. Languages that have no translation are hidden from the widget's language picker.


Endpoints used by the SDK

These endpoints are called automatically - you do not call them directly in normal usage. They use X-API-Key header authentication, not Bearer tokens.

GET/api/v1/consent/public-notice

Fetches the active published consent notice for this tenant, including all purposes, translations, available languages, and DPDPA Rule 3 disclosure fields.

Query

apiKey=dpdpa_live_xxx

Response

{ data: { id, title, purposes[], translations, availableLanguages, contactEmail, complaintText, withdrawalUrl } }
POST/api/v1/consent/sdk-record

Records a consent decision. Called automatically by the SDK on every Accept / Reject All / Save Preferences action. Also callable server-to-server from your backend. Creates an immutable ConsentRecord and stores a SHA-256 proof in S3.

Body

{
  apiKey: string,           // required
  status: 'ACCEPTED' | 'REJECTED' | 'PARTIAL',
  purposes: { [purposeId]: boolean },
  language: string,
  positionShown: string,
  userAgent: string,
  url: string,

  // Identity attribution (optional - choose one):
  identifierHash?: string,  // path 1: 64-char SHA-256 hex
                            // pre-hashed by org backend
  identifier?: string,      // path 2: raw email/phone/userId
                            // hashed server-side by DPDPA Shield
  // If neither provided → falls back to client IP

  // Your own correlation ID (optional, independent of the above):
  externalId?: string,      // e.g. your own users-table primary key
                            // auto-filled from a prior record if omitted
}

Response

{
  data: {
    consentRecordId: string,
    proofHash: string,
    status: "recorded"
  }
}
See for the three identity-hashing paths, and its "Correlating consent to your own users" subsection for what externalId does differently.
POST/api/v1/consent/withdraw-public

Records a consent withdrawal. Called by the Rights Portal withdrawal tab when a data principal submits their email. Rate-limited to 5 requests per IP per hour.

Body

{
  apiKey: string,
  email: string,
  purposeIds?: string[],
  withdrawalReason?: string
}

Response

{
  data: {
    withdrawalId: string | null,  // null if email has no active record
    withdrawnAt: string,
    withdrawnCount: number,       // 0 if email has no active record
    isFullWithdrawal: boolean,
    purposesWithdrawn: string[]
  }
}

Content Security Policy

If your site sends a Content-Security-Policy header you must allow one domainhttps://api.dpdpashield.in — across three directives. All SDK script delivery, API calls, and white-label logo assets are served from this single origin; no S3 bucket domains or CDN hostnames are required.

Content-Security-Policy:
  script-src  'self' https://api.dpdpashield.in;
  connect-src 'self' https://api.dpdpashield.in;
  img-src     'self' data: https://api.dpdpashield.in;
script-srcThe SDK bundle is served from https://api.dpdpashield.in/sdk/dpdpashield-sdk.js. Required for the <script src=...> embed tag to load.
connect-srcThe SDK makes fetch() calls to /api/v1/consent/public-notice, /sdk-record, and /consent/withdraw-public — all on the same origin. The CMP banner additionally calls /api/v1/cmp/config/:tenantId and /cmp/web-event.
img-srcOnly needed if your tenant uses white-label branding with a custom logo. The logo is served through the API proxy (/api/v1/white-label/logo/*) rather than directly from S3, so no bucket hostname is required. data: covers any inline SVG or base64 images.

If you use a nonce-based CSP

The SDK script tag is added statically to your HTML — use your framework's nonce injection to add the nonce attribute to it, or add 'nonce-{YOUR_NONCE}' to script-src alongside the domain allowlist. The SDK itself injects no inline scripts.


Common issues

Need help integrating?

Our team responds within one business day.

Email hello@dpdpashield.in →