---
title: "JavaScript API"
description: "Explicit rendering, programmatic execution and single-page application integration for the Edge Shield widget, using its small global JavaScript API."
url: "https://edge.network/docs/shield/js-api"
section: "Shield"
---

# JavaScript API

The widget renders implicitly from markup by default, and exposes a small global API for explicit rendering, SPAs, and on-demand verification.

## Implicit rendering

With no JavaScript on your side, the script scans for `.edge-shield[data-sitekey]` elements on load, renders each one, and appends a hidden `edge-shield-response` input to the enclosing form:

```html
<script src="https://shield.edge.network/api.js" defer></script>
<div class="edge-shield" data-sitekey="es_..."></div>
```

## Explicit rendering

For full control, render programmatically. `edgeShield.render()` returns a widget ID used with the other methods:

```js
const widgetId = edgeShield.render(document.getElementById('my-container'), {
  sitekey: 'es_...',
  mode: 'managed',            // optional
  callback: (token) => {      // token issued / refreshed
    submitButton.disabled = false
  },
  errorCallback: (err) => {   // verification failed
    console.warn('shield:', err)
  },
  expiredCallback: () => {    // token expired (auto re-verifies)
    submitButton.disabled = true
  },
})
```

## Methods

```js
edgeShield.getResponse(widgetId)  // current token, or null
edgeShield.reset(widgetId)        // clear the token and re-verify
edgeShield.execute(widgetId)      // run verification on demand (invisible mode)
```

| Method | Description |
|---|---|
| `render(el, options)` | Render a widget into a container. Returns a widget ID. Options mirror the data attributes. |
| `getResponse(id?)` | The current token, or `null` if not yet verified. Omit the ID to use the first widget. |
| `reset(id?)` | Clear the current token and run verification again. |
| `execute(id?)` | Run verification on demand. This is the usual pattern for invisible mode (for example, just before submit). |

## Single-page applications

In an SPA, render explicitly when your form mounts and send the token with your API request instead of relying on a form post:

```js
// React example: render on mount, clean up by resetting
useEffect(() => {
  const id = edgeShield.render(containerRef.current, {
    sitekey: 'es_...',
    callback: setToken,
  })
  return () => edgeShield.reset(id)
}, [])

// Submit the token with your API call
await fetch('/api/signup', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email, 'edge-shield-response': token }),
})
```

> [!NOTE]
> Tokens auto-refresh about a minute before their 5-minute expiry, and the `callback` fires again with the fresh token. Keep your local copy up to date from the callback rather than caching the first value.

## Next steps

- [Server-side validation](/docs/shield/siteverify) — Validate tokens from your backend
- [Widget modes](/docs/shield/widget-modes) — Data attributes and mode behaviour
