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

# Embed the Email Canvas

> Embed a Brew group or one email using a client ID, with live generation, multiplayer presence, manual editing, and the editor panel.

Embed Brew's email canvas inside your app with a client ID and exactly one
`groupId` or `emailId`. Customers can see live generation, review emails together,
edit manually, and use the editor panel. No Clerk keys, Brew login, or browser
API key is required.

## Create a Client App

Select the brand in Brew and open **Settings → API → Client apps**.
Choose **Create client ID**, name the app, add its allowed origins, and save.
Copy the client ID into your app.

Allow exact origins such as `https://app.example.com` or
`http://localhost:3500`. Include the port when applicable.

Paths, trailing slashes,
and wildcards are not accepted. HTTPS is required except for loopback development.
Choose whether customers can edit in the client app's settings.

## Install the SDK

Use SDK 12.3.0 or newer:

```bash theme={null}
npm install @brew.new/sdk@^12.3.0
```

The [open source demo](https://github.com/GetBrew/typescript-sdk/tree/main/examples/embedded-email-canvas)
installs the released SDK from npm. It requires no local SDK build or Bun installation.

## Embed a Group or One Email

```tsx theme={null}
'use client'
import { EmailCanvas } from '@brew.new/sdk/react'

export function CustomerEmails() {
  return (
    <EmailCanvas
      clientId="brew_client_..."
      groupId="grp_..."
      style={{ height: '80vh' }}
    />
  )
}
```

For a single email, replace `groupId` with `emailId`. Passing both or neither is
rejected by TypeScript and at runtime.

The client ID determines the brand and
editing permissions. You do not supply user, brand, permission, origin, or session
fields to the browser component.

React 18 and 19 are supported. The component defaults to 640px tall.

Authentication
and automatic session renewal run inside the SDK without replacing the iframe.
The canvas works when third-party login cookies are disabled.

The SDK stores a public recovery ID for each client app in your app's local storage.
This lets it recover unsaved drafts after a reload. Session ownership secrets stay in memory.

If local storage is unavailable, the canvas still works, but cross-reload recovery is unavailable.

### Use Another Framework

```ts theme={null}
import { createEmailCanvas } from '@brew.new/sdk/embed'

const canvas = createEmailCanvas(document.getElementById('canvas')!, {
  clientId: 'brew_client_...',
  emailId: 'email_...',
  onReady: () => console.log('Ready'),
  onError: (error) => console.error(error.code, error.message),
})

// After onReady, and before navigation:
await canvas.flush()
canvas.destroy()
```

Give the container a nonzero height. `fitView()`, `focusEmail(emailId)`, and
`flush()` return promises.

React exposes the same methods through an
`EmailCanvasHandle` ref. Await `flush()` before leaving; a failed save should keep
the canvas mounted so the customer can retry. Use `onDirtyChange` to warn before
navigation, `onSaved` for save feedback, and `onSelectionChange` for selection.

## Use Brew Headlessly

Use the browser canvas as your editing surface and Brew's API for generation
and management. API keys stay on your backend:

```ts theme={null}
// Your backend only
import { createBrewClient } from '@brew.new/sdk'

const brew = createBrewClient({
  apiKey: process.env.BREW_API_KEY!,
  brandId: process.env.BREW_BRAND_ID!,
})

await brew.emails.generate({
  prompt: 'Create a product update email for our subscribed customers.',
  groupId: 'grp_...',
})
```

Keep the matching group canvas mounted while your backend generates emails.
New emails and generated content appear live.

Use `brew.emailGroups` to manage
groups and `brew.emails` to manage designs. Return an authorized email ID when
opening a single-email editing step. A client ID cannot authorize API generation,
sending, or management.

Use cases include:

* An email builder inside your SaaS product
* A shared workspace that displays generation results
* A single-email editor within an approval flow
* A review portal with editing disabled

## Understand the Access Boundary

Client IDs are public app credentials. Brew checks the browser's Origin against
the client's allowlist before issuing short-lived credentials.

The iframe accepts framing only from that origin. Every content, edit, and presence operation
rechecks the client configuration and brand access.

A client ID authenticates the configured app, not an individual person. Visitors
to an allowed origin can request groups and emails within its bound brand.
Opaque target IDs and hiding a target in your UI do not provide per-user access
control.

Non-browser callers can forge Origin headers. For tenant isolation, use
a dedicated brand and client app per customer. For private per-user or per-target
access, use your own login and the advanced server-authorized flow below.

Revoking a client app in Settings ends its established canvas access. Changing
origins or editing permissions invalidates existing sessions; customers can reopen
the canvas. SDK unmount closes its owned session on a best-effort basis; server
expiration handles lost connections.

Multiplayer provides live presence, selections, and saved updates. One person
edits an email at a time. It does not provide simultaneous character-level editing.

The editor panel supports text, color, spacing, layout, image upload, and cropping.
Workspace media search, logos, Giphy, and AI image generation require separate
capabilities and are not included in the embedded panel.

## Advanced Per-User Authorization

Use this when individual users need narrower access than the client app's brand.
No specific login provider is required. Replace `clientId` with a provider that
calls your authenticated endpoint:

```tsx theme={null}
import { EmailCanvas } from '@brew.new/sdk/react'
import { createCanvasSessionProvider } from '@brew.new/sdk/embed'

const getSession = createCanvasSessionProvider('/api/brew/canvas-session')

<EmailCanvas emailId="email_..." getSession={getSession} />
```

Your endpoint receives `{ target, sessionId? }`.
Authenticate the caller and resolve the allowed brand and target from your own data.

Use a server-side API key to call
`brew.canvas.sessions.create({ target, user: { externalId, name }, parentOrigin, permissions })`.

Retain session ownership in your backend. Renew only the caller's owned grant with
`brew.canvas.sessions.refresh(sessionId)`, and revoke it when access ends.
A session ID alone is not proof of ownership.

Never pass both `clientId` and
`getSession`.

## Run the Open Source Demo

The [MIT Next.js demo and README](https://github.com/GetBrew/typescript-sdk/tree/main/examples/embedded-email-canvas)
show client ID setup, group and single-email views, autosave feedback, failed-save
recovery, and save-before-navigation. No authentication-provider keys or API key
are needed to run the demo. The README includes installation, tests, deployment,
and the headless use cases above.

Before release, test your deployed HTTPS app from an allowed and a denied origin.
Confirm the CDN preserves the iframe's framing policy, then upload, crop, save,
and reopen a real image. Local fixture tests do not verify production CDN or
object-storage configuration.

## Need Help?

Our team is ready to support you at every step of your journey with Brew. Choose the option that works best for you:

<Tabs>
  <Tab title="Self-Service Tools">
    <CardGroup cols="2">
      <Card title="Search Documentation" icon="magnifying-glass" color="#c44925">
        Type in the "Ask any question" search bar at the top left to instantly find relevant documentation pages.
      </Card>

      <Card title="ChatGPT/Claude Integration" icon="robot" color="#c44925">
        Click "Open in ChatGPT" at the top right of any page to explore it further with ChatGPT or Claude.
      </Card>
    </CardGroup>
  </Tab>

  <Tab title="Talk to Our Team">
    <CardGroup cols="2">
      <Card title="Schedule a Call" icon="calendar" color="#c44925" href="https://calendar.google.com/calendar/u/0/appointments/schedules/AcZssZ1iYoRUG1J792XQpbuQLjSRRDupr7MwraFK-HQRCtTYdBmrQi8nZu2qXfzKQigb8gbKJK3KN3-R">
        Book time with our founders for personalized guidance on strategy, best practices, or complex implementation questions.
      </Card>

      <Card title="Call Us Directly" icon="phone" color="#c44925">
        Need immediate assistance? Reach us at **+1-(332)-203-2145** for urgent issues or time-sensitive questions.
      </Card>

      <Card title="Slack Channel" icon="slack" color="#c44925">
        Our preferred support channel. You'll receive an invite after signup for direct founder support and fast responses.
      </Card>

      <Card title="Email Support" icon="envelope" color="#c44925" href="mailto:support@brew.new">
        Contact us at **[support@brew.new](mailto:support@brew.new)** for detailed inquiries or if you prefer not to use Slack.
      </Card>
    </CardGroup>
  </Tab>
</Tabs>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.