連携
アプリにエディターを埋め込む
Bannerify のエディターを自社のプロダクトに組み込み、ユーザーがあなたのテンプレートでデザインできるようにする方法を説明します。
ユーザーが、プロダクトの中でバナー、投稿、ラベル、ドキュメントを作る必要があるときは、埋め込みを使います。ページには、iframe で Bannerify のエディターが表示されます。ユーザーごとに自分のデザインを持ち、ワークスペースのテンプレートから始めることもできます。
仕組み
- サーバーが、埋め込みの署名シークレットで、ユーザー用の短いトークンに署名します。
- ページが、iframe で
https://embed.bannerify.co/<embed id>?token=<token>を開きます。 - Bannerify が、トークンとページのドメインを確認し、そのユーザー用のエディターを開きます。
- ユーザーのデザインは、ワークスペースのテンプレートです。ほかのテンプレートと同じように、API で描画します。
前提条件
- Scale プランまたは Enterprise プランのワークスペース。
- JWT に署名できるサーバー。署名シークレットは、サーバー上に置いてください。
| Scale | Enterprise | |
|---|---|---|
| 許可するドメイン | 3 | 8 |
| エディターユーザー | 100 | 500 |
| ダウンロード、権限、名前、ロゴ、アクセントカラー | あり | あり |
| SDK のイベントとコマンド | あり | あり |
| Webhook | あり | あり |
| Bannerify のブランド表示を非表示にする | なし | あり |
| アプリからのアセットピッカー | なし | あり |
| アナリティクス | なし | あり |
埋め込みを設定する
- ダッシュボードのサイドバーで Embed を開きます。
- Set up the embed をクリックし、Turn on the embed をオンにします。
- Allowed domains に、エディターを表示する各ページのオリジンを追加します(例:
https://app.example.com)。すべてのサブドメインにはhttps://*.example.comを、開発中はhttp://localhost:3000を使います。 - 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 に、ページのオリジンを追加します。 |