ナビゲーション

連携

アプリにエディターを埋め込む

Bannerify のエディターを自社のプロダクトに組み込み、ユーザーがあなたのテンプレートでデザインできるようにする方法を説明します。

ユーザーが、プロダクトの中でバナー、投稿、ラベル、ドキュメントを作る必要があるときは、埋め込みを使います。ページには、iframe で Bannerify のエディターが表示されます。ユーザーごとに自分のデザインを持ち、ワークスペースのテンプレートから始めることもできます。

仕組み

  1. サーバーが、埋め込みの署名シークレットで、ユーザー用の短いトークンに署名します。
  2. ページが、iframe で https://embed.bannerify.co/<embed id>?token=<token> を開きます。
  3. Bannerify が、トークンとページのドメインを確認し、そのユーザー用のエディターを開きます。
  4. ユーザーのデザインは、ワークスペースのテンプレートです。ほかのテンプレートと同じように、API で描画します。

前提条件

  • Scale プランまたは Enterprise プランのワークスペース。
  • JWT に署名できるサーバー。署名シークレットは、サーバー上に置いてください。
Scale Enterprise
許可するドメイン 3 8
エディターユーザー 100 500
ダウンロード、権限、名前、ロゴ、アクセントカラー あり あり
SDK のイベントとコマンド あり あり
Webhook あり あり
Bannerify のブランド表示を非表示にする なし あり
アプリからのアセットピッカー なし あり
アナリティクス なし あり

埋め込みを設定する

  1. ダッシュボードのサイドバーで Embed を開きます。
  2. Set up the embed をクリックし、Turn on the embed をオンにします。
  3. Allowed domains に、エディターを表示する各ページのオリジンを追加します(例: https://app.example.com)。すべてのサブドメインには https://*.example.com を、開発中は http://localhost:3000 を使います。
  4. Embed id と Signing secret をコピーします。

サーバーでトークンに署名する

トークンは、HS256 の JWT です。sub には、アプリでのユーザー ID を設定します。同じ sub は、常に同じデザインを開きます。

import { SignJWT } from "jose"

const token = await new SignJWT({ sub: user.id, name: user.name, email: user.email })
  .setProtectedHeader({ alg: "HS256" })
  .setExpirationTime("1h")
  .sign(new TextEncoder().encode(process.env.BANNERIFY_EMBED_SECRET))
クレーム 必須 説明
sub いいえ アプリでのユーザー ID。英数字、_、-、@、. で、256 文字まで。指定しない場合、エディターはワークスペースのテンプレートを編集します。
name いいえ ユーザーの名前。
email いいえ ユーザーのメールアドレス。
exp はい トークンの有効期限。現在から最大 24 時間後まで。

エディターを表示する

<iframe
  src="https://embed.bannerify.co/emb_xxx?token=TOKEN"
  style="width: 100%; height: 800px; border: 0"
  allow="clipboard-write"
></iframe>

URL に &templateId=tpl_xxx を付けると、1 つのデザインを直接開きます。

SDK を使う

SDK は、iframe を追加し、ユーザーの操作をページに伝え、ページからエディターを制御できるようにします。

npm install @bannerify/embed
import { createBannerifyEmbed } from "@bannerify/embed"

const embed = createBannerifyEmbed({
  container: document.getElementById("editor"),
  embedId: "emb_xxx",
  token, // signed by your server
})

embed.on("template:update", ({ template }) => {
  console.log("Saved", template.id)
})

React では、@bannerify/embed-react をインストールし、コンポーネントを使います。ref でエディターを制御します。

npm install @bannerify/embed-react
import { BannerifyEmbed, type BannerifyEmbedHandle } from "@bannerify/embed-react"

const editor = useRef<BannerifyEmbedHandle>(null)

<BannerifyEmbed
  ref={editor}
  embedId="emb_xxx"
  token={token}
  style={{ height: 800 }}
  onDownload={({ fileName, content }) => upload(fileName, content)}
/>

イベント

イベント React の prop データ
ready onReady { user }。この時点から、エディターがコマンドを受け付けます。
template:open onTemplateOpen { template, canEdit }。ワークスペースのテンプレートでは、canEdit が false です。
template:close onTemplateClose { templateId }
template:create onTemplateCreate 新しいデザインまたはコピーの { template }。
template:update onTemplateUpdate 保存または名前変更の後の { template }。
template:delete onTemplateDelete { templateId }
download onDownload { templateId, format, fileName, content }。content は、ファイルのデータ URL です。
error onError エディターを開けなかったときの { message }。
asset:request onAssetRequest { requestId, type }。アセットピッカーを参照してください。

template には、id、name、width、height、updatedAt があります。

コマンド

各コマンドは、ready を待ってから、Promise を返します。

コマンド 結果
openTemplate(templateId) { template }。ユーザーのデザイン、またはワークスペースのテンプレートを開きます。
closeTemplate() デザインの一覧に戻ります。
setModifications([{ name, text, color, src, qrcode, barcode, visible }]) { changed }。API の modification と同じように、開いているデザインのレイヤーを名前で変更します。
save() { template }。開いているデザインを保存します。
requestContent(format) { templateId, content }。開いているデザインを、png、jpeg、webp、pdf として描画します。

ワークスペースのテンプレートは読み取り専用のため、setModifications と save は “Make a copy of this template to change it” で失敗します。

requestContent は、エディターでのダウンロードや API での描画と同じように、1 回ごとにワークスペースの 1 生成分になります。ワークスペースが生成回数を使い切っている場合、ダウンロードはエディターにエラーを表示し、requestContent はそのエラーで失敗します。

アセットピッカー

Enterprise プランでは、ユーザーが画像を追加したり色を選んだりするときに、ページ独自のライブラリを表示できます。Asset picker の下で、Images from your app または Colors from your app をオンにします。すると、Media パネルにアプリ名つきの Choose from が表示され、カラーピッカーにはスウォッチのボタンが加わります。ユーザーは、自分のファイルをアップロードすることもできます。

const embed = createBannerifyEmbed({
  container,
  embedId: "emb_xxx",
  token,
  onAssetRequest: async ({ type }) => {
    if (type === "image") {
      const photo = await openMyMediaLibrary() // your own UI
      return photo ? { url: photo.url, fileName: photo.name } : null
    }
    const hex = await openMyBrandColors()
    return hex ? { value: hex } : null
  },
})

ユーザーがピッカーを閉じたときは、null を返します。Bannerify は、https の URL から画像をダウンロードし、ユーザーのアップロードにコピーするため、その後は URL が失効してもかまいません。画像は、PNG、JPEG、WebP、SVG で、5 MB までです。React では、同じ関数を onAssetRequest として渡します。

SDK を使わない場合

エディターは、postMessage でページとやり取りします。エディターを囲むページに { source: "bannerify-embed", type, data } を送り、そのページからの { source: "bannerify-host", type, requestId, data } だけを受け付けます。各コマンドには、{ source: "bannerify-embed", type: "response", requestId, data } で応答し、エラーの場合は data の代わりに error を入れます。コマンドの種類は、open-template、close-template、set-modifications、save、request-content、asset-response です。asset:request イベントには、asset-response とデータ { requestId, asset } で応答します。asset は、{ url, fileName }、{ value }、null のいずれかです。

ユーザーにできること

  • 一般的なサイズでデザインを作成するか、ワークスペースのテンプレートをコピーする。
  • テキスト、画像、図形、QR コード、そのほかエディターのレイヤーを編集する。
  • 自分の画像をアップロードする。
  • デザインを、PNG、JPEG、WebP、PDF としてダウンロードする。ダウンロードは、1 回ごとにワークスペースの 1 生成分になります。

これらは、Permissions の下で、それぞれオンとオフを切り替えられます。Appearance の下では、エディター上部の名前とロゴ、主要なボタンのアクセントカラーを設定します。

ユーザーのデザインを描画する

テンプレート一覧の embedUserId パラメーターで、1 人のユーザーのデザインを一覧表示し、ほかのテンプレートと同じように描画します。

curl "https://api.bannerify.co/v1/templates?apiKey=bnfy_xxx&embedUserId=user_123"

ユーザーのテンプレートは、ダッシュボードのテンプレート一覧には表示されません。

Webhook

Webhook の下に URL を追加すると、ユーザーがデザインを作成、変更、削除したときに、サーバーが POST を受け取ります。SDK のイベントは、開いているページにしか届かないため、自分の記録を保つために使います。

{
  "id": "eev_01J9X...",
  "type": "template.create",
  "createdAt": "2026-10-19T08:00:00.000Z",
  "embedId": "emb_xxx",
  "user": { "id": "user_123" },
  "template": { "id": "tpl_xxx", "name": "Summer sale", "width": 1080, "height": 1080 }
}
type タイミング
template.create ユーザーがデザインを始めたか、テンプレートをコピーしました。
template.update ユーザーがデザインを保存したか、名前を変更しました。
template.delete ユーザーがデザインを削除しました。
test Send test event をクリックしました。user と template は null です。

sub のないトークンでは、user は null です。10 秒以内に 2xx のステータスで応答してください。失敗した配信は、1、2、4、8、16、32 分後に再試行されます。同じイベントには、常に同じ id が付くため、すでに処理した id はスキップしてください。

署名を確認する

各リクエストには、Bannerify-Signature ヘッダー(t=<unix seconds>,v1=<signature>)が付きます。署名は、<t>.<raw body> を Webhook のシークレットで HMAC-SHA256 にかけた、16 進数の値です。

import { createHmac, timingSafeEqual } from "node:crypto"

const verify = (rawBody: string, header: string, secret: string) => {
  const { t, v1 } = Object.fromEntries(header.split(",").map((part) => part.split("=")))
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex")
  return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
}

パースする前に、生のボディを読み取ってください。パースしてから再度シリアライズしたボディは、バイト列が変わることがあります。

アナリティクス

Enterprise プランでは、Embed ページの Analytics セクションに、過去 7 日、30 日、90 日のユーザーのエディターの使われ方が表示されます。ユーザー、セッション、作成されたデザイン、ダウンロード、1 日あたりのセッション数、エディターを開いたサイト、最もアクティブなユーザーです。セッションは、エディターを 1 回読み込むことです。日付は UTC です。

署名シークレットをローテーションする

シークレットが漏えいしたときは、Rotate secret をクリックします。古いシークレットで署名したトークンは、すぐに使えなくなるため、先にサーバーを更新してください。

トラブルシューティング

メッセージ 対処
The embed token is not valid 現在の署名シークレットで、alg を HS256 にして、exp クレームを付けてトークンに署名します。
This embed is turned off ダッシュボードで埋め込みをオンにします。
This app reached its limit of editor users 各 sub が 1 ユーザーとして数えられます。ユーザー数を増やすには、Enterprise にアップグレードします。
This app used all its generations for this month ダウンロードは、ワークスペースの生成として数えられます。毎月 1 日のリセットを待つか、プランを変更します。
ページにエディターが表示されない Allowed domains に、ページのオリジンを追加します。