Versioned notices, unbundled per-purpose consent, and a hash-chained consent ledger with notice-content evidence. Under 5 KB. No database access. Free to start.
We process your personal data for the purposes below. Choose each one separately — you can change or withdraw any of them later, in the same number of steps.
No consent platform can make you “DPDP compliant”, ours included, and anyone selling you that is selling you a problem. This handles the obligations that live at the point of collection and the point of request. The rest stays with you, and your dashboard says so in plain terms. Not sure where you actually stand? Take the free 3-minute self-check.
Wired up the moment the script loads.
We can evidence these. We cannot do them for you.
None of this is conceptually hard. It is just a lot of fiddly, legally-load-bearing detail that has nothing to do with your product.
Publish a reviewed notice with a captured policy snapshot or PDF. Every affirmative decision is bound to that exact version and content hash.
Reviewed translations are not available yet, so the product does not claim them.
Per-purpose toggles, nothing pre-ticked, and “Reject all” given exactly the same prominence as “Save choices”. The widget will not let you ship a bundled consent flow even if you try.
s.6(1) and s.6(4), enforced in the component.
Every grant and withdrawal becomes a hash-chained record carrying the notice version, locale, timestamp, and the affirmative action captured. Evidence is retained immutably and viewable by the tenant owner.
This is the artifact you produce when asked to prove consent.
Requester verification, SLA clocks, and signed webhooks are the next Indie release. They are deliberately not presented as available today.
Until then, fulfil rights requests through your own product support flow.
Under 5 KB gzipped, async, no dependencies, served from the edge. Consent decisions evaluate locally against a cached ledger — no network call in your hot path.
If our edge is down the widget renders from cache and queues.
No VPC peering, no database credentials, no collector to deploy, no security review. We never see your data — only pseudonymous references and the consent decisions themselves.
Which is also why signup is instant.
The production script tag gets you a reviewed notice and consent. React helpers and rights webhooks are planned releases, not current dependencies. allows() only stops your own code from calling a tracker — gate the tracker's own tag (the “Block trackers” tab) and sp.js stops it from ever loading at all, not just from being told to be quiet. This is opt-in per script: anything you don't mark this way loads exactly as it always did.
<script src="https://cdn.scalepulse.in/sp.js" data-key="pk_live_7f3a…" data-endpoint="https://ingest.scalepulse.in/" // required, not optional data-purposes="analytics,marketing.email,personalisation" data-lang="auto" // Eighth Schedule detection, manual switcher defer ></script> // Without data-endpoint, sp.js posts events to {src origin}/v1/e by // default — the CDN serving this script has no such route, so events // fail silently with a CORS error in the console. // Read a decision anywhere. Local, no network call. <script> if (window.ScalePulse.allows('analytics')) { initAnalytics(); } </script>
Paste this into your own agent, in your own project. It finds your actual trackers, gates the ones it can, and tells you plainly about the ones it can't — it never guesses your public key or invents a purpose id. Runs entirely in your codebase; we never see it.
You are integrating ScalePulse, a DPDP (India's Digital Personal Data Protection Act) consent widget, into this codebase. Work directly in this project — do not fetch anything from the internet, and do not invent values you were not given.
GOAL
Every visitor sees a consent banner before any optional tracker runs, and every optional tracker (analytics, marketing, advertising — never anything required to operate the site) is blocked until its specific purpose is granted.
STEP 1 — Before changing anything, ask me for:
- The ScalePulse public key (looks like pk_live_... or pk_test_...). Never invent one or leave a placeholder in code you present as done.
- The exact purpose ids I declared in my ScalePulse notice (e.g. "analytics", "marketing.email"). Every data-sp-category you write below must match one of these exactly — a typo'd or invented category id means that tracker silently never unblocks, with no error anywhere.
STEP 2 — Add the widget once, site-wide (root layout / base template / <head>), not per-page. data-endpoint is not optional — without it sp.js defaults to POSTing events at {the script's own src origin}/v1/e, which is just the static CDN and has no such route, so every consent event fails silently with a CORS error in the console:
<script
src="https://cdn.scalepulse.in/sp.js"
data-key="THE_KEY_FROM_STEP_1"
data-endpoint="https://ingest.scalepulse.in/"
data-purposes="analytics,marketing.email"
data-lang="auto"
defer
></script>
STEP 3 — Find every third-party analytics/marketing/advertising script in this codebase: Google Analytics (gtag.js / analytics.js), Google Tag Manager, Meta/Facebook Pixel, LinkedIn Insight Tag, Hotjar, TikTok Pixel, or anything similar. Search broadly — a <script src="..."> tag in HTML or a template, a Next.js <Script> component, a Vue/Svelte/Angular component that mounts one conditionally, a WordPress plugin's injected snippet, or application code that calls document.createElement('script') to load one.
STEP 4 — For a static tag with a src, add type="text/plain" and data-sp-category, keep everything else:
BEFORE: <script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
AFTER: <script type="text/plain" data-sp-category="analytics" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
STEP 5 — For an inline block (tracker init code with no src), wrap the whole tag the same way and do not touch the JS inside it:
BEFORE: <script>fbq('init', 'PIXEL_ID'); fbq('track', 'PageView');</script>
AFTER: <script type="text/plain" data-sp-category="marketing.email">fbq('init', 'PIXEL_ID'); fbq('track', 'PageView');</script>
STEP 6 — For a tracker your OWN application code loads programmatically (not a static tag — e.g. a function that injects a script element on some condition, or a framework component that mounts one), do not try to force it into the type="text/plain" pattern. Gate the call itself instead, and re-check on every consent change:
if (window.ScalePulse?.allows('analytics')) loadGoogleAnalytics();
window.ScalePulse?.on(() => {
if (window.ScalePulse.allows('analytics')) loadGoogleAnalytics();
});
STEP 7 — Add a way for a visitor to change their mind later — s.6(4) requires withdrawal to be as easy as giving consent, and a gated tracker that got granted once otherwise stays granted forever with no way back. Simplest option, a "Privacy choices" or "Cookie preferences" link, typically in the site footer, that reopens the full banner on the current page:
<a href="#" onclick="window.ScalePulse.show(); return false;">Privacy choices</a>
If this project already has its own settings/preferences page and a full banner reopen would be out of place there, use window.ScalePulse.set(purposeId, granted) to drive per-purpose toggles directly in that existing UI instead — it records the same kind of affirmative action as the banner. Pair it with window.ScalePulse.on(fn) to keep any toggle UI in sync if consent changes elsewhere (e.g. the visitor used the banner in another tab). Do not build a custom toggle UI unless one already exists to integrate with — the banner is the tested, compliant default.
If a hosted consent page (a custom domain like privacy.<their-domain>/consent) is configured for this tenant, link to that too — ask me whether one exists rather than guessing a domain.
STEP 8 — Do not touch anything required for the site to function: login, checkout/payments, the framework's own runtime scripts, accessibility tooling, error monitoring you consider operationally necessary. Only gate analytics/marketing/advertising trackers. If you are unsure whether something counts as "necessary," ask me — do not guess.
STEP 9 — Flag rather than silently skip anything you cannot gate this way: a script injected by a CDN/edge/reverse-proxy layer rather than appearing anywhere in this codebase (e.g. an "automatic setup" analytics option, some platform-level Shopify/WordPress built-ins) cannot be intercepted by any client-side consent tool, ours included, because there is no tag in the source to mark. Tell me explicitly which trackers fall into this category instead of leaving them silently unblocked.
STEP 10 — When done, report back: every tracker you found, what you changed for each one, the withdrawal link you added, and anything from step 9 you could not gate and why.
Why type="text/plain" and not something like data-consent="pending": a <script> whose type is not a recognised JavaScript MIME type is never fetched or executed by the browser at all — a denied tracker makes zero network requests. It is not loaded quietly or told to behave; it never runs. Withdrawing consent later cannot un-execute a script that already ran in this page view — it only stops the next one from starting, which is why this re-evaluates fresh on every page load.allows() covers the common case. The rest is for building your own UI instead of the banner — a settings page, a footer link, or linking consent to a signed-in account.
| Method | Returns | What it does |
|---|---|---|
allows(purposeId) | boolean | Synchronous, local, no network call. Read-only. |
set(purposeId, granted) | Promise<void> | Grants or withdraws one purpose as a real affirmative action — recorded to the ledger the same as a banner click. No-ops on a necessary purpose. |
show() | void | Reopens the full banner for the visitor to choose themselves. |
on(fn) | () => void | Subscribe to every consent change. Call the returned function to unsubscribe. |
withdrawAll() | void | Withdraws every non-necessary purpose at once. |
identify(subjectToken) | void | Attaches an opaque, pre-HMACed token to every event from this point on, to link consent to a known account. Raw user IDs are rejected. |
ready | Promise<void> | Resolves once the widget has finished its initial boot. |
| ScalePulse Indie | Enterprise CMP | Build it yourself | |
|---|---|---|---|
| Time to live | Minutes | Weeks — scoping, onboarding, review | Weeks of your own time |
| Cost | Free, then ₹999/mo | Annual contract, sales-led | Your time, plus translation |
| Reviewed translations | In build | Usually available | You commission and maintain them |
| Integration | One script tag | Tag manager, config, often a CSM | You own every edge case |
| Database access | None | Often a collector or VPC peering | N/A |
| Consent proof | Hash-chained, exportable | Yes | Whatever you remembered to log |
| Rights portal | In build | Yes, usually a paid module | Another project |
The middle column is a generic characterisation of enterprise consent platforms, not a claim about any named vendor — their pricing is contract-specific and we are not going to invent numbers for it. Compare against your own quotes.
The free tier is generous because it costs us close to nothing to run at the edge — not as a trap with a cliff at the end.
For a side project, a launch, or your first hundred users.
When it is a real product with real users and a brand.
Several products, a team, and someone asking about SLAs.
The script is under 5 KB gzipped, has no dependencies, loads defer, and is served from the edge. It does not block render and it does not touch your critical path.
After the first load, consent decisions are read from a local cache, so allows() is synchronous and sub-millisecond. The size budget is enforced by a CI check that fails our build if it regresses.
No — and you cannot, on this tier. There is no collector, no VPC peering, and no credentials to hand over. We only ever see pseudonymous references and the consent decisions themselves.
That is also the limitation: because we cannot see your data, we cannot scan it for retention overruns or find personal data you forgot about. That is the platform product, and it is a different kind of install.
Only for scripts you mark that way. Wrap the tracker's own tag as <script type="text/plain" data-sp-category="…"> (the “Block trackers” install tab) and it is never fetched or executed until that purpose is granted — not loaded quietly, not loaded and told to behave, genuinely never requested. A tag manager container only needs its one loader tag gated; whatever it injects afterward inherits that.
Anything you do not mark this way is untouched and loads exactly as it always did — this is opt-in per script, not a blocklist that recognises trackers by name. It also cannot reach a script your CDN or edge provider injects into the page itself rather than your own template (some “automatic setup” analytics options work this way) — there is no tag in your source to mark, and no client-side consent tool, ours included, can intercept that.
Not yet. We support the locale you publish today. Reviewed translations are a separate programme because machine-translating legal notices is not a defensible substitute.
The dashboard will show locale coverage once translated notice versions and reviewer sign-off are available. Until then, do not represent the widget as meeting the multi-language requirement.
Today, they use your own support or account flow. ScalePulse currently records consent decisions; its verified rights portal and webhook routing are the next Indie release.
Your app does the deleting. We cannot reach your data. Until the portal launches, you must track verification, fulfilment, and response timing yourself.
No, and we are careful about this. “Consent Manager” is a defined role under the Act — a registered intermediary through which a Data Principal can give, manage, review, and withdraw consent, subject to registration and eligibility criteria set by the Board.
ScalePulse is a consent management platform: software you, the Data Fiduciary, use to discharge your own obligations. You remain the Data Fiduciary and we act as your Data Processor. If you need a registered Consent Manager, you need a registered entity, and we will say so rather than blur it.
No. Today it covers versioned notice and consent capture. Rights-request handling, security safeguards, retention, processor contracts, and breach notification remain your obligations.
Security safeguards, retention limits, contracts with your processors, and breach notification remain your obligations. The coverage panel above is the same one in your dashboard, and it is deliberately blunt about the gap.
One script tag, a purpose list, and you have defensible consent records from your very next visitor. Everything else can come later.