---
url: https://docs.ridgedata.ai/guide/iframe.md
---
# Iframe quickstart

Add an iframe with a signed Ridge URL to display a dashboard in your app. You do not need an
API key, a token endpoint, or JavaScript.

## 1. Generate a signed URL

Open the dashboard's **Embed** dialog in Ridge, choose **Iframe Embed**, and generate a URL.
If the dashboard uses partitioned data, choose the viewer's partition before generating it.
The partition is covered by the URL signature and cannot be changed by editing the URL.

See [Iframe authentication](./iframe-authentication) for URL expiration and revocation, and
[Partitioning](./partitioning) for row-level access.

Treat the signed URL as a credential. Anyone who has it can view the dashboard and its permitted data until
you revoke it in Ridge. An open iframe keeps working until its next token renewal; see
[Lifecycle and revocation](./iframe-authentication#lifecycle-and-revocation).

## 2. Add the iframe

```html
<iframe
  id="ridge-dashboard"
  src="SIGNED_RIDGE_EMBED_URL"
  title="Sales dashboard"
  width="100%"
  height="640"
  style="border: 0"
></iframe>
```

The iframe loads the dashboard and its data from Ridge, using the dashboard's published theme.

## 3. Optional: control state from the host

The frame sends `ridge:ready` once it can accept commands. Replies and events are addressed
to the origin of the first message your app sends, so send a command after `ridge:ready` even
if you only want to listen. See [Host origin](./iframe-authentication#host-origin).

Register the listener before loading the signed URL. For this example, create the iframe
from step 2 **without its `src` attribute** and set it at the end of the script:

```js
const frame = document.querySelector("#ridge-dashboard");
const signedUrl = "SIGNED_RIDGE_EMBED_URL";
const ridgeOrigin = new URL(signedUrl).origin;
const readyTimeout = setTimeout(() => {
  console.warn(
    "No ridge:ready received. Check loading errors and that this listener ran before the frame loaded."
  );
}, 15_000);

window.addEventListener("message", (event) => {
  if (event.source !== frame.contentWindow || event.origin !== ridgeOrigin) return;

  if (event.data?.type === "ridge:ready") {
    clearTimeout(readyTimeout);
    console.log("Dashboard ready", event.data.stateSchema);
    frame.contentWindow.postMessage(
      {
        type: "ridge:setState",
        state: { "region-menu": { filter: "EMEA" } }
      },
      ridgeOrigin
    );
  }
  if (event.data?.type === "ridge:stateChange") {
    console.log("Dashboard state", event.data.state);
  }
  if (event.data?.type === "ridge:error") {
    console.warn("Dashboard rejected a write", event.data.error);
  }
});

frame.src = signedUrl;
```

The timeout is a diagnostic. A failed load, a revoked URL, or a slow network can all prevent
readiness. Inspect the iframe's network requests and browser console.

See [Dashboard state](./state#read-state) for reads, writes, and request
ids.

## Revoking access

Revoke the signed URL from the dashboard's **Embed** dialog. The dashboard and other generated
URLs remain available.
