> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getimmutable.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Embeddable Viewer

> Embed a read-only audit log viewer in your application using JWT tokens.

## Overview

The embeddable viewer lets you display audit log events directly in your application without proxying through your backend. You generate a short-lived JWT token scoped to specific filters, then pass it to a frontend component or iframe.

## Creating a Viewer Token

Generate a token server-side using the API:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://getimmutable.dev/api/v1/viewer-token \
    -H "Authorization: Bearer imk_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "tenant_id": "org_7rT2xBc",
      "ttl": 3600
    }'
  ```

  ```typescript JavaScript theme={null}
  const { token, expires_at } = await client.createViewerToken({
    tenantId: "org_7rT2xBc",
    ttl: 3600,
  });
  ```

  ```php Laravel theme={null}
  $result = AuditLog::createViewerToken([
      'tenantId' => 'org_7rT2xBc',
      'ttl' => 3600,
  ]);
  ```
</CodeGroup>

### Parameters

<ParamField body="tenant_id" type="string">
  Restrict the viewer to events for a specific tenant. Use this to show customers only their own events.
</ParamField>

<ParamField body="actor_id" type="string">
  Restrict the viewer to events by a specific actor.
</ParamField>

<ParamField body="ttl" type="integer" default="3600">
  Token lifetime in seconds. Minimum 60, maximum 86400 (24 hours). Default 3600 (1 hour).
</ParamField>

### Response

```json theme={null}
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": 1774537200
}
```

## Embedding with an iframe

The simplest approach is an iframe:

```html theme={null}
<iframe
  src="https://getimmutable.dev/viewer?token=eyJhbGciOiJIUzI1NiIs..."
  width="100%"
  height="600"
  frameborder="0"
  style="border-radius: 8px;"
></iframe>
```

## React Component Example

A reusable React component that handles token generation and display:

```tsx theme={null}
"use client";

import { useEffect, useState } from "react";

interface AuditLogViewerProps {
  token: string;
  height?: number;
}

export function AuditLogViewer({ token, height = 600 }: AuditLogViewerProps) {
  const [iframeSrc, setIframeSrc] = useState<string | null>(null);

  useEffect(() => {
    setIframeSrc(`https://getimmutable.dev/viewer?token=${token}`);
  }, [token]);

  if (!iframeSrc) return null;

  return (
    <iframe
      src={iframeSrc}
      width="100%"
      height={height}
      style={{ border: "none", borderRadius: "8px" }}
      title="Audit Log"
    />
  );
}
```

Generate the token server-side and pass it as a prop:

```tsx theme={null}
// Server component
import { immutable } from "@/lib/immutable";
import { AuditLogViewer } from "./audit-log-viewer";

export default async function CustomerDashboard({ tenantId }: { tenantId: string }) {
  const { token } = await immutable.createViewerToken({
    tenantId,
    ttl: 3600,
  });

  return (
    <div>
      <h2>Activity Log</h2>
      <AuditLogViewer token={token} />
    </div>
  );
}
```

## TTL Management

Tokens are short-lived by design. For long-running pages, refresh the token before it expires:

```typescript theme={null}
// Refresh token 5 minutes before expiry
const ttl = 3600;
const refreshInterval = (ttl - 300) * 1000;

setInterval(async () => {
  const { token } = await fetch("/api/viewer-token").then((r) => r.json());
  setIframeSrc(`https://getimmutable.dev/viewer?token=${token}`);
}, refreshInterval);
```

## Security

<Note>
  Viewer tokens are **read-only**. They cannot be used to ingest events, modify settings, or access any write endpoints. It is safe to expose them to end users in the browser.
</Note>

The token's JWT claims encode the filters you specified. The viewer backend validates these claims and only returns matching events. Users cannot modify the token to access events outside the specified scope.
