How to Integrate Custom Addons with Stremio Web: A Complete Technical Guide

Stremio Web integrates custom addons by parsing URL parameters (type, catalogId, transportUrl) in the useRemoteAddons hook and dispatching a Load action to the CatalogWithFilters model, enabling remote catalog fetching without local installation.

The Stremio Web client provides a flexible architecture for loading third-party content sources through its Addons route. According to the Stremio/stremio-web source code, the application distinguishes between locally installed addons and remote catalogs, allowing developers to integrate custom addons either through deep links or direct programmatic access.

Understanding the Addon Integration Architecture

Stremio Web manages addon discovery through two specialized React hooks that handle different data sources.

useRemoteAddons (located in src/routes/Addons/useRemoteAddons.js) constructs the Load/Unload actions for remote catalogs based on URL query parameters. When valid parameters are detected, this hook generates the necessary model state to fetch content from an external manifest.

useInstalledAddons (located in src/routes/Addons/useInstalledAddons.js) serves as a fallback mechanism, loading the list of locally persisted addons when no remote parameters are present in the URL.

The main Addons component (src/routes/Addons/Addons.js) orchestrates these hooks, rendering the catalog selector UI and handling the installation flow through useAddonDetailsTransportUrl.

Preparing Your Custom Addon

Before integration, your addon must expose a JSON manifest compliant with the Stremio addon specification. The manifest URL acts as the transportUrl parameter.

Ensure your manifest includes:

  • Valid content types (movie, series, channel, etc.)
  • Catalog definitions with unique identifiers
  • Proper CORS headers for cross-origin requests

Method 1: URL-Based Integration (Deep Linking)

The simplest way to integrate a custom addon is through URL parameters that trigger the remote loading mechanism.

Construct a URL with three required parameters:

  • type — The primary content type (e.g., movie, series)
  • catalogId — The catalog identifier defined in your manifest (e.g., mycatalog)
  • transportUrl — URL-encoded address of the manifest file
https://app.strem.io/addons?type=movie&catalogId=mycatalog&transportUrl=https%3A%2F%2Fmyserver.com%2Fmanifest.json

When a user navigates to this URL, useRemoteAddons validates the parameters and returns a Load action:

{
    action: 'Load',
    args: {
        model: 'CatalogWithFilters',
        args: {
            request: {
                base: urlParams.transportUrl,
                path: {
                    resource: 'addon_catalog',
                    type: urlParams.type,
                    id: urlParams.catalogId,
                    extra: []
                }
            }
        }
    }
}

This action is passed to useModelState (from stremio/common), which instructs the core to fetch the remote catalog via src/core/createTransport.ts.

Method 2: Programmatic Integration

For components that need to load custom addons without modifying the URL, reuse the same model action pattern directly.

Create a custom hook that wraps useModelState:

const React = require('react');
const { useModelState } = require('stremio/common');

const useCustomAddon = (manifestUrl, type, catalogId) => {
    const action = React.useMemo(() => ({
        action: 'Load',
        args: {
            model: 'CatalogWithFilters',
            args: {
                request: {
                    base: manifestUrl,
                    path: {
                        resource: 'addon_catalog',
                        type,
                        id: catalogId,
                        extra: []
                    }
                }
            }
        }
    }), [manifestUrl, type, catalogId]);

    return useModelState({ 
        model: 'remote_addons', 
        action, 
        deps: ['ctx'] 
    });
};

// Usage in a component
function MyComponent() {
    const manifestUrl = 'https://myserver.com/manifest.json';
    const { selectable, selected } = useCustomAddon(manifestUrl, 'movie', 'mycatalog');
    
    // selectable contains available catalogs
    // selected contains the active catalog data
    return null;
}

Core Implementation Details

The Remote Addons Hook (useRemoteAddons.js)

Located at src/routes/Addons/useRemoteAddons.js, this hook reads URL search parameters using useSearchParams. When all three parameters (type, catalogId, transportUrl) are present and valid strings, it constructs the Load action for the CatalogWithFilters model. If parameters are missing or invalid, it returns an Unload action to clear the remote state.

The Installed Addons Fallback (useInstalledAddons.js)

Found at src/routes/Addons/useInstalledAddons.js, this hook loads the user's locally installed addons as a fallback. It queries the core model for installed addon data, providing the base list shown in the Addons selector when no remote URL parameters are active.

The Addons Component (Addons.js)

The main container at src/routes/Addons/Addons.js composes both hooks and manages the UI state. It uses useSelectableInputs (from src/routes/Addons/useSelectableInputs.js) to merge remote and installed catalogs into a unified selector. When users interact with the "Add Addon" input, it updates addonDetailsTransportUrl via useAddonDetailsTransportUrl, syncing the modal input with the route parameters.

Transport Layer (createTransport.ts)

The core transport implementation in src/core/createTransport.ts handles the actual HTTP requests to fetch remote manifests. When the CatalogWithFilters model receives a Load action, it uses this transport layer to retrieve the addon manifest and subsequent catalog data, parsing the responses into the Stremio content format.

Summary

  • Stremio Web distinguishes between remote and installed addons through separate hooks in the Addons route.
  • URL parameters (type, catalogId, transportUrl) trigger automatic loading via useRemoteAddons when navigating to /addons.
  • Programmatic access requires creating a Load action for the CatalogWithFilters model and passing it to useModelState with the remote_addons model key.
  • Core files involved include useRemoteAddons.js, useInstalledAddons.js, Addons.js, and createTransport.ts.
  • Manifest compliance is required—custom addons must serve valid JSON manifests with proper CORS configuration.

Frequently Asked Questions

How does Stremio Web validate custom addon URLs?

Stremio Web validates custom addon URLs in src/routes/Addons/useRemoteAddons.js by checking that type, catalogId, and transportUrl are all non-empty strings. If any parameter is missing or invalid, the hook returns an Unload action instead of attempting to fetch the remote catalog.

Can I integrate a custom addon without installing it permanently?

Yes. When you access an addon via URL parameters or programmatic Load actions, Stremio Web treats it as a remote catalog without persisting it to local storage. The addon remains available only for the current session unless the user explicitly clicks the Install button rendered by the Addon component in src/routes/Addons/Addon/Addon.js.

What model does Stremio Web use to fetch addon catalogs?

Stremio Web uses the CatalogWithFilters model to fetch addon catalogs. As implemented in the source code, this model accepts a request object with a base (the manifest URL) and a path specifying the resource type, content type, catalog ID, and extra parameters. The core then uses createTransport.ts to execute the HTTP request.

How do I test a custom addon during development?

You can test a custom addon by navigating to the Addons page with your manifest URL as the transportUrl parameter, or by using the Discover flow in src/routes/Discover/Discover.js. For programmatic testing, create a temporary component that calls useModelState with a manually constructed Load action pointing to your local or staging manifest endpoint.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →