# 自作のニュースレターフォームの登録を beehiiv に送る

> 自作の登録フォームを beehiiv につなぎます。リレーがダブルオプトインをオンにし、設置場所を UTM ソースに、ページをリファラーにして各購読を作成します。

公開日 2026-10-25 · https://ikiform.com/ja/guides/newsletter-signup/beehiiv

自作のフォームを Ikiform に送信し、Webhook を beehiiv の購読作成エンドポイントを呼ぶリレーに向けます。beehiiv が確認メールを送るよう `double_opt_override: "on"` を送り、フォームの設置場所を `utm_source` に、ページを `referring_site` に渡し、登録が配信停止をひそかに取り消さないよう `reactivate_existing` は false のままにします。1 件の登録につき API の呼び出しは 1 回で、キーはリレーに置いたままです。

## beehiiv で異なる点

beehiiv の API はパブリケーションを中心に構成されています。購読とは 1 つのパブリケーションに登録されたメールアドレスのことで、`/v2/publications/{publicationId}/subscriptions` への 1 回の `POST` で作成します。登録に関することはすべてその 1 回のリクエストで送ります。確認を求めるか、ウェルカムメールを送るか、読者がどこから来たか、カスタムフィールドです。[Kit](https://ikiform.com/ja/guides/newsletter-signup/kit.md) のような、タグやフォームの別の手順はありません。

beehiiv は獲得経路も UTM の用語で記録します。購読の記録には `utm_source`、`utm_medium`、`utm_campaign`、`referring_site` が含まれます。フォームのフィールドをこれらに対応付ければ、beehiiv の各購読者に、どの設置場所とどの記事から来たかが表示されます。

図: リレーが Ikiform の送信データを beehiiv の購読に対応付ける方法

1. fields.email は email になります。
2. fields.source は utm_source になります。
3. meta.referrer は referring_site になります。
4. fields.first_name は custom_fields の First Name になります。
5. double_opt_override: "on" はリレーが追加します。
6. reactivate_existing: false はリレーが追加します。

最初の 4 つは Ikiform のイベントから来ます。最後の 2 つは、リレーがすべての登録で決めている固定の選択です。

## beehiiv を設定する

1. beehiiv で **Settings** を開き、**Workspace Settings** の **API** で **Create New API Key** を選びます。beehiiv は二度と表示しないので、すぐにコピーしてください。
2. 有料プランなら、キーをフォームの送信先となる 1 つのパブリケーションに限定します。パブリケーションに限定したキーはほかのパブリケーションでは `404` になるので、漏れたときの被害を抑えられます。
3. パブリケーションの id を確認します。beehiiv の API がパスで使う、接頭辞付きの id です。API のパブリケーション一覧のエンドポイントが返します。
4. 名を保存したいなら、`First Name` という名前のカスタムフィールドを作ります。beehiiv はまだ存在しないカスタムフィールドを破棄します。
5. ダブルオプトインとウェルカムメールはパブリケーションの設定で用意します。リレーはリクエストごとにそれらをオンにし、内容は beehiiv にあります。

> beehiiv の料金ページではすべてのプランに API アクセスが記載されており、安いプランほど API のレート制限が低くなっています。API でメールを送るための Send API は上位プランに限られますが、このリレーは購読を作成するだけなので不要です。

## リレー

これは Netlify Function で、すでに Netlify にあるサイトに向いています。静的サイトの隣で、自分のドメイン上で、別のサービスなしに動きます。型のために `@netlify/functions` をインストールし、3 つの変数をサイトの環境設定に設定します。

`netlify/functions/beehiiv.mts`:

```ts
import type { Config } from "@netlify/functions";
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";

export default async (request: Request) => {
  const payload = await request.text();
  let event;
  try {
    event = await verifyWebhook({
      payload,
      headers: request.headers,
      secret: Netlify.env.get("IKIFORM_WEBHOOK_SECRET")!,
    });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return new Response(error.reason, { status: 400 });
    throw error;
  }
  if (event.type !== "submission.created") return new Response(null, { status: 204 });

  const { email, first_name, consent, source } = event.data.fields;
  if (consent !== true || typeof email !== "string") return new Response("Skipped", { status: 200 });

  const publication = Netlify.env.get("BEEHIIV_PUBLICATION_ID");
  const answer = await fetch(`https://api.beehiiv.com/v2/publications/${publication}/subscriptions`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${Netlify.env.get("BEEHIIV_API_KEY")}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      email,
      double_opt_override: "on",
      send_welcome_email: true,
      reactivate_existing: false,
      utm_source: typeof source === "string" ? source : "website",
      utm_medium: "signup_form",
      referring_site: event.data.meta.referrer ?? undefined,
      custom_fields: typeof first_name === "string" && first_name ? [{ name: "First Name", value: first_name }] : [],
    }),
  });

  if (answer.status === 429) {
    const reset = Number(answer.headers.get("ratelimit-reset"));
    const wait = reset ? Math.max(1, reset - Math.floor(Date.now() / 1000)) : 60;
    return new Response("beehiiv rate limit", { status: 503, headers: { "retry-after": String(wait) } });
  }
  if (!answer.ok) return new Response(`beehiiv answered ${answer.status}: ${await answer.text()}`, { status: 502 });
  return new Response(null, { status: 204 });
};

export const config: Config = {
  path: "/hooks/beehiiv",
};
```

- `double_opt_override: "on"` は、パブリケーションのデフォルトにかかわらず確認メールを送ります。パブリケーションの設定に従うなら `"not_set"` を使い、公開フォームでは決して `"off"` にしないでください。
- API では `send_welcome_email` のデフォルトは `false` です。埋め込みからの登録と同じウェルカムメールを API での登録にも送りたいなら、`true` にします。
- `reactivate_existing: false` もデフォルトです。配信停止した人を再び有効にしてしまうので、あとで誰かが深く考えずに切り替えないよう、明記しておきます。
- beehiiv は購読を付けて `200` を返します。その `status` は、beehiiv がアドレスを確認している間は `validating` で始まり、読者が確認するまでは `pending` です。
- `429` のとき、リレーは beehiiv の `RateLimit-Reset`（Unix 時刻）を読み、Ikiform 向けの `Retry-After` の待ち時間に変換します。

関数の URL は `https://your-site.com/hooks/beehiiv` です。Ikiform の **Webhooks** に追加し、`whsec_` のシークレットを `IKIFORM_WEBHOOK_SECRET` にコピーします。URL のルールは [Webhook のドキュメント](https://ikiform.com/ja/docs/webhooks.md)に、処理済みの配信を飛ばす方法は[自前のサーバー](https://ikiform.com/blog/form-submissions-to-your-own-server.md)にあります。

## UTM の値を決める

beehiiv の UTM のフィールドは自由記述なので、値は一度決めたら一貫させてください。そうしないと、`footer` と `Footer` のようなほぼ重複した記録に分かれてしまいます。フォームの非表示の `source` 入力欄が、そのまま `utm_source` になります。`utm_medium` は固定にして、自分のフォームからの登録を beehiiv のホスト型ページやインポートと区別できるようにします。

| 設置場所 | `source` 入力欄 | `utm_source` | `utm_medium` |
| --- | --- | --- | --- |
| サイトのフッター | `footer` | `footer` | `signup_form` |
| 記事の最後 | `post` | `post` | `signup_form` |
| ニュースレターのページ | `newsletter-page` | `newsletter-page` | `signup_form` |

フォームのあるページにリンクするキャンペーンを行うなら、リレーでページの URL からキャンペーンを読み取ります。`meta.referrer` にはページの完全な URL が入り、ブラウザーが送っていればクエリ文字列も含まれるので、リレーはそこから `utm_campaign` パラメーターをリクエストにコピーできます。

## プランごとのレート制限

beehiiv は上限を API キーごとに固定の 60 秒の枠で測り、上限はプランによって異なります。1 件の登録が 1 リクエストです。

| beehiiv のプラン | 1 分あたりのリクエスト数 |
| --- | --- |
| Free | 30 |
| Lite | 180 |
| Pro | 500 |
| Enterprise | 800、申請すればそれ以上 |

1 分あたり 30 件あれば、たいていのフッターのフォームには十分ですが、無料のパブリケーションでのローンチ記事なら超えることもあります。リレーの `503` で、Ikiform は登録を捨てずに待ってからリトライします。プラン名と上限は変わるので、自分のプランが載っていなければ beehiiv のレート制限のページを確認してください。

## ハマりどころ

- **カスタムフィールドの名前は完全一致。** beehiiv はカスタムフィールドを名前で照合し、未知のものはエラーではなくレスポンスの警告付きで捨てます。打ち間違いがあると、名が知らないうちに欠けていきます。
- **`referring_site` は空のことがある。** ブラウザーがリファラーを送らなかった場合、`meta.referrer` は `null` になり、リレーはそのフィールドを省きます。
- **既存の購読者。** beehiiv のドキュメントには、この呼び出しで購読が作成または更新されるとありますが、アクティブな購読者で何が変わるかは書かれていません。すべてのページにフォームを置く前に、自分の確認済みのアドレスでテストしてください。
- **キーはデフォルトでワークスペース全体が対象。** パブリケーションを限定していないキーは、ワークスペースのすべてのパブリケーションにアクセスできます。範囲を絞ってください。
- **有料ティアは beehiiv の中で。** `tier` を省けば、登録者は有料購読なしで加わります。アップグレードは beehiiv 自身の決済で行われます。

## 動作を確認する

1. Ikiform でエンドポイントの **Send test** を選びます。配信には `204` が表示され、beehiiv にはリクエストが届きません。
2. 自分のアドレスでページから購読します。配信には `204` が表示されます。
3. beehiiv では、購読者が pending として、設置場所を UTM ソース、記事をリファラーとして表示されます。
4. ダブルオプトインのメールが届きます。確認すると、ウェルカムメールが続いて届きます。
5. beehiiv でそのアドレスを配信停止にし、もう一度登録します。`reactivate_existing` が false なので、購読者は非アクティブのままです。

## よくある質問

### beehiiv の埋め込みの代わりに、自作のフォームを使えますか？

はい。フォームを Ikiform に送信し、登録ごとにリレーに beehiiv の購読作成エンドポイントを呼ばせます。フォームは自分のデザインのまま、読者への確認、歓迎、メール配信は引き続き beehiiv が行います。

### beehiiv の API はすべてのプランで使えますか？

beehiiv の料金ページではすべてのプランに API アクセスが記載されており、レート制限のページでは最も安いプランは 1 分あたり 30 リクエストです。Send API は上位プランに限られますが、購読の作成には使いません。

### API での登録に beehiiv からダブルオプトインのメールを送らせるには？

購読作成のリクエストで double_opt_override を "on" にして送るか、パブリケーション自身の設定を使うなら "not_set" にします。"off" にすると、メールなしで購読者がすぐにアクティブになります。

### コードなしで beehiiv につなげますか？

はい。beehiiv は Zapier や Make で使え、レート制限はそれらが守ってくれます。Ikiform の Webhook を自動化ツールに向け、その beehiiv のアクションで購読者を追加してください。

## その他のガイド

- [ニュースレター登録フォーム](https://ikiform.com/ja/guides/newsletter-signup.md): 自分のマークアップでニュースレター登録フォームを作り、同意を記録し、ボットの登録を防ぎ、購読者を Kit、MailerLite、beehiiv など任意のツールに渡します。
- [ダブルオプトイン](https://ikiform.com/ja/guides/newsletter-signup/double-opt-in.md): Ikiform は確認メールを送らないので、ダブルオプトインはメールツールで行います。中継が各登録を未確認として追加し、ツールがリンクを送ります。
- [静的サイト](https://ikiform.com/ja/guides/newsletter-signup/static-site.md): Hugo、Jekyll、Eleventy、Astro の静的サイトにニュースレター登録フォームを追加し、メールツールの API キーをページに入れず、確認はツールで行います。
- [Kit (ConvertKit)](https://ikiform.com/ja/guides/newsletter-signup/kit.md): 購読者を作成し、特典メールのために Kit のフォームに追加し、設置場所のタグを付けるリレーで、自作のニュースレターフォームを Kit につなぎます。
- [MailerLite](https://ikiform.com/ja/guides/newsletter-signup/mailerlite.md): 自作の登録フォームを MailerLite につなぎます。リレーが新しい読者をダブルオプトインのために未確認として追加し、購読者に二度確認を求めることはありません。
- [Next.js のニュースレターフォーム](https://ikiform.com/ja/guides/newsletter-signup/nextjs.md): Next.js のフッターのニュースレターフォームです。同意のチェックと Turnstile を行うサーバーアクションが Ikiform に送信し、ルートハンドラーが読者を Kit に追加します。
