File DA-023 View as Markdown

Plugins

A plugin lets you send Double Agent's verdict to a tool we don't support yet, or send each session to your own backend. Every built-in integration is a plugin, and so is the Double Agent cloud, so you can also run with the cloud off.

The shape of a plugin

doubleagent.use({
  name: 'mytool',                 // unique; a later plugin with the same name replaces it
  cat: 'analytics',               // consent category: 'analytics' (default) | 'ads' | 'functional'
  setup(ctx) { return () => {} }, // once per session; the teardown runs on reset() and pagehide
  apply(verdict, ctx) {},         // every new verdict; ctx.event is 'da_classified' / 'da_final' once per session
  report(payload, ctx) {},        // the session report; payload.reason is 'ready' | 'change' | 'hidden' | 'pagehide' | 'flush'
});
  • A plugin you add is always on. It runs only when the visitor consented to its cat.
  • Before the script loads, queue it: doubleagent.push('use', plugin). With npm: init({ plugins: [plugin, [other, config]] }).
  • ctx.fields holds the nine da_* properties. ctx.config is the second

argument of use().

  • ctx.send(url, body) posts JSON as text/plain, so there is no CORS preflight. It tries sendBeacon first, then a

keepalive fetch.

  • A plugin that throws is skipped (and logged with debug: true). Other plugins and your page carry on.

Send verdicts to a tool we don't support

Everything stays in the browser. Nothing leaves the page except through the tool itself.

doubleagent.push('use', {
  name: 'acme',
  apply(v, ctx) {
    if (!ctx.allowed) return;
    window.acme?.setUserProperties({ da_class: ctx.fields.da_class, da_score: ctx.fields.da_score });
    if (ctx.event) window.acme?.track(ctx.event, ctx.fields);
  },
});

Send sessions to your backend

Your server gets the same session reports as the Double Agent cloud.

doubleagent.push('use', {
  name: 'mybackend',
  report(p, ctx) {
    ctx.send('https://collect.example.com/da', { reason: p.reason, sid: p.sid, verdict: p.verdict, pages: p.pages });
  },
});

Cloud off, your own backend only

Use this when no data may go to Double Agent. The script still detects in the page and your plugins still run.

<script>window.doubleagent=window.doubleagent||{q:[],push(){this.q.push(arguments)}};
doubleagent.push('use', { name: 'mybackend', report(p, ctx) { ctx.send('https://collect.example.com/da', p); } });</script>
<script async src="https://cdn.doubleagent.so/v1/doubleagent.js" data-cloud="off"></script>

With npm: doubleagent.init({ cloud: false, plugins: [mybackend] }).

With the cloud off, the script makes no request to Double Agent. Verdicts, integrations and your plugins keep working. What needs the cloud stops:

  • check(), getToken() and stripeToken() reject with DoubleAgentError code cloud_disabled.
  • protect() does nothing: the form submits without a da_token.
  • on('final') never fires, because final verdicts come from the server.
  • No data in the portal, no live presence, no proof of work, no server checks of agent identity.

Next: Capabilities to compare what works with and without the cloud, or Agent Detector to run the engine on its own.