メインコンテンツへスキップ
Nuxt 3, 4 で構築されたサイトに Turnint AI の埋め込みスクリプトを組み込む方法をまとめます。nuxt-module の追加や独自の plugin / composable は基本的に不要で、app.vue でスクリプトを 1 度読み込めば、あとは data-turnint-* 属性または window.turnintai.open() で起動できます。
動作する完全なサンプルを公開しています。以下のコードはこの repo の japanese-landing-page/ ディレクトリと一致しています。手元で動かしたい場合は repo を clone して pnpm install && pnpm dev で起動してください。

3 つの組み込みパターン

パターン使いどころ必要な実装
A. ボタンで開くLP の CTA、ヘッダーやフッターの「資料を見る」など、ユーザー操作で起動したいdata-turnint-* 属性を付けたボタン
B. ページ表示時に自動で開く専用ルート(例: /start)に着地したら即座に viewer を立ち上げたいonMountedwindow.turnintai.open() を呼ぶ
C. インライン表示ページ内の特定領域に viewer をそのまま埋め込みたいdata-turnint-* 属性を付けた <div>
いずれのパターンでも、共通の前提として embed script をアプリ全体で 1 度だけ読み込む 必要があります。次のセクションで設定します。

共通: embed script を読み込む

app/app.vue(Nuxt 4)または app.vue(Nuxt 3)で useHead を使い、Turnint AI の embed script を <head> に注入します。
<script setup>
useHead({
  script: [
    {
      src: "https://cdn.turnint.ai/js/latest/turnint.ai.embed.js",
      async: true,
      defer: true,
    },
  ],
})
</script>

<template>
  <div>
    <NuxtRouteAnnouncer />
    <NuxtPage />
  </div>
</template>
asyncdefer を付けることで、初期描画をブロックせずにスクリプトを読み込めます。読み込みが完了すると window.turnintai が利用可能になり、以後すべてのページで起動 API が使えます。
スクリプトは app.vue で 1 度だけ読み込めば十分です。各ページで個別に useHead を呼ぶ必要はありません。

パターン A: ボタンクリックで開く

最もシンプルな方法です。任意の要素に data-turnint-* 属性を付与すると、その要素がクリックされたタイミングで viewer が開きます。
<template>
  <button
    data-turnint-id="pub_xxxxxxxxxxxxxxxx"
    data-turnint-type="fullscreen"
    data-turnint-locale="ja"
  >
    AI と資料を読む
  </button>
</template>
属性値の例説明
data-turnint-idpub_xxxxxxxxxxxxxxxx開きたいコンテンツの ID。ダッシュボードから取得
data-turnint-typefullscreen / popover開き方。fullscreen は画面全体を覆うモーダル、popover はチャットバブル
data-turnint-localeja / en / autoviewer の UI 言語。auto でブラウザ言語を自動検出
Nuxt の <NuxtLink> でページ遷移した後に新しく追加されたボタンも、自動で検知されて起動可能になります。route 変更ごとに手動で再マウントする必要はありません(詳しくは後述の「SPA ナビゲーションについて」を参照)。

パターン B: ページ表示時に自動で開く

「LP の CTA から専用ページに飛ばし、着地した瞬間に viewer を立ち上げたい」というユースケース向けのパターンです。専用の空白ページを 1 つ作り、onMounted 内で window.turnintai.open() を呼びます。
<!-- app/pages/start.vue -->
<script setup lang="ts">
import { onMounted } from "vue"

type TurnintAI = {
  open(config: {
    deckId?: string
    type?: "fullscreen"
    locale?: "ja" | "en" | "auto"
    onClose?: () => void
  }): void
}
type WindowWithTurnintAI = Window & typeof globalThis & { turnintai?: TurnintAI }

onMounted(() => {
  const openWhenReady = () => {
    const w = window as WindowWithTurnintAI
    if (w.turnintai) {
      w.turnintai.open({
        deckId: "pub_xxxxxxxxxxxxxxxx",
        locale: "ja",
      })
      return
    }
    requestAnimationFrame(openWhenReady)
  }
  openWhenReady()
})
</script>

<template>
  <section />
</template>
embed script は async で読み込んでいるため、onMounted の発火時点ではまだ window.turnintai が定義されていない可能性があります。requestAnimationFrame でフレームごとに再チェックすることで、ロード完了直後に確実に open() を呼び出せます。
type: "fullscreen" 以外の指定は現状サポートされていません。インライン表示が必要な場合はパターン C を使ってください。

パターン C: インライン表示

ページ内の特定領域に viewer を埋め込みたい場合は、<div> などに data-turnint-* 属性を付けます。data-turnint-type を省略するか、button / a 以外のタグを使うと、自動でインラインモードとして描画されます。
<template>
  <div
    data-turnint-id="pub_xxxxxxxxxxxxxxxx"
    data-turnint-locale="ja"
    style="height: 600px;"
  />
</template>
要素の高さは CSS 側で確保してください(viewer は親要素のサイズに合わせて描画されます)。

TypeScript で型を効かせる

window.turnintai の公式型定義はパッケージとしては配信していないため、プロジェクト側で型を宣言します。types/turnintai.d.ts のようなファイルを作成し、以下を貼り付けてください。
// types/turnintai.d.ts
export {}

declare global {
  interface Window {
    turnintai?: {
      open: (config: {
        deckId?: string
        type?: "fullscreen"
        endpoint?: string
        locale?: "ja" | "en" | "auto"
        onClose?: () => void
      }) => void
    }
  }
}
Nuxt は tsconfig.json を自動生成するため、types/ ディレクトリに置けば自動的に読み込まれます。明示的に取り込みたい場合は nuxt.config.tstypescript.tsConfig.include に追加してください。

関連ドキュメント