Publishers
SDK integration and user consent
The SDK collects URLs and search queries, so under GDPR (art. 6) and ePrivacy (art. 5(3)) it needs explicit user consent. Until the user presses “Allow”, the SDK creates no identifier, stores no events and contacts no server. Your extension works the same either way.
Installation
In the dashboard: Extensions → SDK → “Download”. Download the single .js file and place it in your extension root as intentd.min.js. The file carries your keys and configuration. Do not rename it.
manifest.json
background.js
popup.html
intentd.min.js the SDK carrying your extension keys — do not rename {
"manifest_version": 3,
"background": { "service_worker": "background.js", "type": "module" },
"action": { "default_popup": "popup.html" },
"permissions": ["storage", "webNavigation", "tabs", "alarms", "unlimitedStorage"],
"host_permissions": ["https://api.intentd.net/*"]
} // background.js — first line, at the top level
import './intentd.min.js'; Consent Flow
An extension with a popup
Call IntentD.mountConsent() in your popup. Until the user allows collection there, the SDK stays inactive — making the call is the extension’s responsibility.
<div id="consent-root"></div>
<!-- ... your extension UI ... -->
<script src="intentd.min.js"></script>
<script src="popup.js"></script> // The banner appears only when there is no consent for the current text version.
// The promise resolves with the user's choice: true — allowed, false — declined.
IntentD.mountConsent(document.getElementById('consent-root')); The banner renders in a closed Shadow DOM: your styles do not affect it, its styles do not affect you. The theme (light or dark) is picked from the popup background, and the width ranges from 320 to 800 px. “Decline” and “Allow” are the same size, and nothing is pre-ticked. After consent the banner disappears for good; after a decline it comes back the next time the popup opens.
An extension without a popup
Not supported yet. The single-file download has no separate consent page, so the consent banner needs a popup to be shown in. Write to us if your extension has no popup.
When the prompt appears
| Event | Behaviour |
|---|---|
| Popup opened | The banner, if you call mountConsent and there is no consent |
| Any other service worker wake-up | Nothing is shown |
| Consent already given | The banner is no longer shown |
| Consent text version changed | Consent is requested again |
Withdrawing consent
The consent text promises the user they can withdraw it in the settings. Add a toggle to your options page:
const allowed = await IntentD.hasConsent();
// "Withdraw consent" button
await IntentD.revokeConsent(); // collection stopped, local data deleted
// "Allow collection" button (after a decline, for instance)
await IntentD.grantConsent(); Do not add your popup to web_accessible_resources
Extension pages are reachable by the extension itself without that list. If the page showing the banner becomes web-accessible, any site can frame it and quietly harvest an “Allow” click — and consent obtained that way is not valid.
API
| Method | Purpose |
|---|---|
| IntentD.mountConsent(element) | Show the banner in the popup when there is no consent. Promise<boolean>. |
| IntentD.hasConsent() | Whether consent exists for the current text version. Promise<boolean>. |
| IntentD.getConsentState() | 'approved' | 'declined' | null. |
| IntentD.grantConsent() | Record consent (from your own UI). |
| IntentD.revokeConsent() | Withdraw: collection stops, the queue and the installation identifier are deleted. |
| IntentD.openConsentTab() | Open the consent tab (or focus the open one). Reserved for extensions without a popup, which the single-file download does not support yet. |
| IntentD.status() | SDK state, including consent and paused: 'limit_reached' | null. |
The decision is stored only in chrome.storage.local of that browser profile: every device asks separately, and the server does not record who consented or when. Only the consent text version travels to the server with each bucket.
When the plan limit is reached
If the plan limit is reached (HTTP 402 SUBSCRIPTION_LIMIT_REACHED), the SDK keeps events queued locally and retries every hour. The extension should call IntentD.status() to detect this and prompt the developer to upgrade.
const status = await IntentD.status();
if (status.paused === 'limit_reached') {
// Events are held in chrome.storage.local and sent after the upgrade.
}