📦

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}',
                  position: 'bottom-right'
                });
              }
              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',
      position: 'bottom-right'
    });
  </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_.
positionstringOptionalWidget anchor position. One of: bottom-right | bottom-left | bottom-center | top-centerDefault: 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.


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',
    position: 'bottom-right'
  });
})();

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
}

Response

{
  data: {
    consentRecordId: string,
    proofHash: string,
    status: "recorded"
  }
}
See for full details on all three identity paths.
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[]
  }
}

Common issues

Need help integrating?

Our team responds within one business day.

Email hello@dpdpashield.in →