Single-page apps and mobile

Use AgentGate from React, Vue and other component frameworks, and inside mobile WebViews.

The SDK is one script with no dependencies and one global, AgentGate. It works the same in server-rendered pages and single-page apps; what changes is when you create and clean up widgets.

Load the script once

Load https://agentgate.example/sdk/v1/agentgate.js once per page load, for example in your HTML shell, and call AgentGate.init() as early as you can. Loading it a second time does nothing: the bundle returns early when window.AgentGate is already present.

JavaScript
AgentGate.init({ siteKey: "site_…", endpoint: "https://agentgate.example" });

init starts the document-wide interaction counters that the check scores. They run for the life of the page, across route changes, and init may be called more than once (later calls only update siteKey and endpoint).

Forms your code submits: use execute()

When your component sends the request itself (fetch, a GraphQL mutation, a form library), call AgentGate.execute() in the submit handler and send the token with the request. There is nothing to mount or unmount.

React

JSX
function ContactForm() {
  async function onSubmit(e) {
    e.preventDefault();
    try {
      const { token } = await AgentGate.execute({ action: "submit" });
      await fetch("/api/contact", {
        method: "POST",
        headers: { "Content-Type": "application/json", "X-AgentGate-Token": token },
        body: JSON.stringify(Object.fromEntries(new FormData(e.currentTarget))),
      });
    } catch (err) {
      // err.code: rate_limited, challenge_failed, canceled, timeout, network, …
      showError(err.code);
    }
  }
  return <form onSubmit={onSubmit}>{/* fields */}<button>Send</button></form>;
}

Vue

JavaScript
async function onSubmit(event) {
  const { token } = await AgentGate.execute({ action: "submit" });
  await fetch("/api/contact", {
    method: "POST",
    headers: { "Content-Type": "application/json", "X-AgentGate-Token": token },
    body: JSON.stringify(Object.fromEntries(new FormData(event.target))),
  });
}
// <form @submit.prevent="onSubmit">…</form>

Call execute() at submit time, not when the component mounts: a token is single use and expires after two minutes by default.

Visible widgets: render() and remove()

To show the managed chip or the interactive Verify button inside a component, render the widget when the component mounts and remove it when it unmounts:

React

JSX
function Widget({ onToken }) {
  const ref = useRef(null);
  useEffect(() => {
    const id = AgentGate.render(ref.current, {
      siteKey: "site_…", action: "submit", mode: "managed",
      callback: (token) => onToken(token),
      expiredCallback: () => onToken(""),
    });
    return () => AgentGate.remove(id);
  }, []);
  return <div ref={ref} />;
}

Vue

JavaScript
// <div ref="host"></div>
onMounted(() => {
  id = AgentGate.render(host.value, { siteKey: "site_…", action: "submit", mode: "managed" });
});
onBeforeUnmount(() => AgentGate.remove(id));

What the lifecycle guarantees:

  • remove(id) cancels a verification in progress and takes back everything the widget added: its submit handler, the agentgate_token field it created (a field your page provides is kept), its elements, its timers and the attributes it set on the host element.
  • React StrictMode's mount, unmount, mount sequence is safe.
  • Rendering into an element that already holds a widget replaces it, so a host never carries two widgets.
  • reset(id) and remove(id) with an id that no longer exists do nothing.

Route changes

Tokens are not tied to a URL within your origin, so a route change does not invalidate anything. The origin matters: the page's origin must be in the site's allowed origins.

Mobile WebViews

Inside a WebView (Android WebView, iOS WKWebView, Capacitor, React Native WebView) the page runs the JavaScript SDK like any browser, with two conditions:

  • the page must be served from an origin in the site's allowed origins. Pages loaded from file:// or a custom scheme send no usable Origin and get origin_denied;
  • JavaScript, fetch and Web Workers must be enabled (without workers the proof of work runs on the main thread, which is slower).

Warning

AgentGate has not yet been measured on mobile hardware or in WebViews, and there is no native iOS or Android SDK. Start such a site in monitor mode and check the would-have decisions for your app's traffic before you enforce.

Native clients that do not render a page (a mobile app calling your API directly) have no browser evidence to give. Protect those routes with the gateway as machine routes (rate policy, rules and agent identity, no browser token).

View as Markdown