nuxt-twitch-ext

Build your Twitch Extension and Extension Backend Service (EBS) in a single Nuxt project.
3,134 1
Install
npm install nuxt-twitch-ext
Latest Version:0.2.11
Vue:3
License:MIT
Last Updated:Oct 1, 2026
Links: GitHub  ·  npm
Maintainer: yizack

nuxt-twitch-ext

npm version npm downloads License

Build your Twitch Extension and Extension Backend Service (EBS) in a single Nuxt project.

Features

  • Manage only one project for the extension and its backend
  • Preview extension pages in Local Test with .html
  • Include the Twitch Extension Helper and type definitions
  • EBS API endpoints with CORS support
  • Client-side utility for EBS calls and public asset paths
  • Server utilities for Twitch JWT verification
  • Package extension environment assets as a ZIP
  • Only extension pages are pre-rendered in the extension build
  • Extension-only pages and assets are excluded from the app build

Quick Setup

  1. Add nuxt-twitch-ext dependency to your project
pnpm add nuxt-twitch-ext
  1. Add the module in your nuxt.config.ts
export default defineNuxtConfig({
  modules: ["nuxt-twitch-ext"],
});

Project Structure

A project structure with default directories might look like this:

app/
├── app.vue                        # Application root
├── pages/
│   ├── index.vue                  # Nuxt main page (Not an extension page)
│   ├── extension/                 # Twitch extension pages
│   │   ├── config.vue
│   │   ├── panel.vue
│   │   ├── mobile.vue
│   │   ├── video_overlay.vue
│   │   └── video_component.vue
│   ├── ...
├── assets/                        # Application assets
│   └── ...
server/
└── api/
    ├── ebs/                       # EBS API endpoints
    │   └── ...
    └── ...

Configuration

Option Default Description
helperScript Twitch's Extension Helper Script included in extension pages
filename 'twitch-ext.zip' Name of the generated archive
pages.dirname 'extension' Directory name for extension pages
pages.prerender ['config', 'panel', 'mobile', 'video_overlay', 'video_component'] Pages to pre-render for the extension
ebs.enabled true Enable the EBS utilities and CORS handling
ebs.dirname 'ebs' Directory name for EBS API endpoints
ebs.baseURL Production URL used by extFetch
ebs.preflight.allowMethods ['GET'] Methods allowed for EBS CORS preflight requests
ebs.preflight.allowHeaders ['Content-Type', 'Authorization'] Headers allowed for EBS CORS preflight requests

For example, customize the archive name and CORS settings:

export default defineNuxtConfig({
  modules: ["nuxt-twitch-ext"],
  twitchExt: {
    filename: "my-extension.zip",
    ebs: {
      baseURL: "https://your-app.example.com",
      preflight: {
        allowMethods: ["GET", "POST"],
        allowHeaders: ["Content-Type", "Authorization", "X-Custom-Header"],
      },
    },
  },
});

[!TIP] When the EBS is enabled, twitchExt.ebs.baseURL must be set to the production URL of the Nuxt server, so that extFetch can correctly target the production EBS endpoints.

Environment Variables

Provide the Twitch Extension Client ID and Extension Secret Key as server-only runtime configuration values.

NUXT_TWITCH_EXT_CLIENT_ID=your-extension-client-id
NUXT_TWITCH_EXT_SECRET_KEY=your-extension-secret-key

Extension Pages

The default directory for extension pages is app/pages/extension/. The directory name for extension pages can be changed with twitchExt.pages.dirname.

When navigating between extension pages, use relative paths (./<page>) instead of root-relative paths (/<page>).

<template>
  <NuxtLink to="./another-page">Another Page</NuxtLink>
</template>

I recommend placing extension assets in the app/assets/ folder and referencing them from your extension pages as ~/assets/<file>. For example:

<template>
  <img src="https://raw.githubusercontent.com/Yizack/nuxt-twitch-ext/HEAD/~/assets/images/logo.png" alt="My Logo" />
</template>

Nuxt processes referenced assets for the extension build; unreferenced files in app/assets/ are not included.

For assets that should be available in all environments, place them in public/. Nuxt serves these files as-is in development and production, and the extension build includes them too.

Use the auto-imported extAsset helper for public assets referenced dynamically in an extension page. It keeps root-relative paths in development and resolves them against the extension assets in a Twitch build:

<template>
  <img :src="extAsset('/images/logo.png')" alt="Logo" />
</template>

Development Environment

In development, extension pages are accessible at root level with .html for easy preview during Twitch Extension Local Test status.

For example, app/pages/extension/<page>.vue can be accessed as /<page>.html

Twitch Extension Build

The module CLI runs Nuxt in twitchExt mode (nuxt-twitch-ext). In this mode, the build only includes pages from app/pages/extension/ (or the directory configured by twitchExt.pages.dirname).

For each extension page:

  1. The extension/ directory segment is removed from the route
  2. If the page name matches one of the twitchExt.pages.prerender values, it is pre-rendered as a root-level HTML file.
  3. Nuxt's inline state is extracted into a sibling JavaScript file

For example:

app/pages/extension/panel.vue

is generated as:

panel.html
panel-nuxt-state.js

Regular application pages, such as app/pages/index.vue, are not included in the extension build.

The build also:

  • Includes the Twitch Extension Helper
  • Uses relative URLs for generated assets
  • Ignores Nuxt's default 200.html and 404.html pages
  • Uses twitchExt.ebs.baseURL as the base URL for the extFetch utility

Production App Environment

When Nuxt runs in production (nuxt build), pages under twitchExt.pages.dirname are excluded from the application routes. Unlike development or the twitchExt build, this does not generate extension pages or package an extension ZIP; regular application pages and endpoints remain available.

When EBS is enabled, the module register a middleware for routes under /api/<twitchExt.ebs.dirname>/** that:

  • Adds https://<client-id>.ext-twitch.tv as the allowed origin in CORS responses.
  • Answers OPTIONS preflight requests with the configured allowed methods and headers.

Call verifyTwitchExtension or verifyTwitchTransaction server utilities in EBS route handlers as appropriate.

Auto Imports

Twitch Extension Client:

  • extAsset(path) returns the path for an asset within the Twitch extension, based on the current navigation URL and origin.
  • extFetch(request, options?) instance of $fetch that fetches data from the EBS endpoints, uses the current origin in development and twitchExt.ebs.baseURL in the generated Twitch extension as the base URL for EBS requests.

Server:

  • verifyTwitchExtension(event) verifies the Twitch JWT token for your extension, returning the verified payload or null if the verification fails.
  • verifyTwitchTransaction(event, receipt) verifies a Bits transaction receipt for your extension, returning the verified payload or null if the verification fails.

Working with the EBS

After Twitch authorizes the extension, extFetch automatically adds the current token as a Bearer token in the Authorization header for requests to the EBS origin. Calls made before authorization do not include the token.

[!IMPORTANT] Add the domain of twitchExt.ebs.baseURL to the Allowlist for URL Fetching Domains in your Twitch Extension Capabilities settings. Without it, requests from the extension to the EBS may be blocked.

<script setup lang="ts">
onMounted(() => {
  Twitch.ext.onAuthorized(async () => {
    const data = await extFetch("/api/ebs/data");
  });
});
</script>

Verify the token in the server route before processing the request:

export default defineEventHandler(async (event) => {
  const payload = await verifyTwitchExtension(event);

  if (!payload) {
    throw createError({
      status: 401,
      message: "Invalid authorization",
    });
  }

  return { channelId: payload.channel_id };
});

[!NOTE] You can set twitchExt.ebs to false to disable the EBS entirely.

Build the Extension

Add the following script to your package.json to build the Twitch extension:

"scripts": {
  "build:twitch-ext": "nuxt-twitch-ext"
}

This runs nuxt generate --envName twitchExt and writes .output/twitch-ext.zip by default. Upload that ZIP in your Twitch Extension files tab in the Twitch developer console.

Caveats

  • An index.vue at the root of the extension pages directory and defined in the twitchExt.pages.prerender array does not generate index.html. With the default pages.dirname: "extension", app/pages/extension/index.vue generates /extension.html.
  • Twitch's Extension Content Security Policy (CSP) blocks inline JavaScript, including inline <script> elements. The extension build moves Nuxt's inline state script to a sibling *-nuxt-state.js file, but custom inline scripts are not rewritten. Put custom JavaScript in Vue component scripts or imported .js/.ts files so Nuxt can bundle it.
  • In the twitchExt build, this module disables unsupported modules such as @nuxtjs/color-mode, @nuxthub/core, and @nuxtjs/sitemap.
  • Referencing assets from the public folder without using extAsset may result in incorrect paths within the Twitch extension.

Related Packages

@scayle/storefront-nuxt

Nuxt integration for the SCAYLE Commerce Engine and Storefront API

152,903
nuxt-tsconfig-stub

Stub Nuxt's generated tsconfig.json at installation

70,835 24
kuranuxt

Look at the Nuxt 3 documentation to learn more.

871 0
nuxt-define

One utility function for module authors to define compiler constants for all bui...

13,412,511
dayjs-nuxt

Day.JS Module for Nuxt

1,986,864 126

Version History

Version Released License
0.2.11 MIT
0.2.10 MIT
0.2.9 MIT
0.2.8 MIT
0.2.7 MIT