Products Services Docs Pricing About Contact Sign In Get Started

Video Players

ImpossibleFX renders personalized videos on demand and returns a standard video URL. You can use that URL as a source in any video player that accepts external media. See Rendering Videos for how to obtain render URLs and tokens.

This page covers the built-in ImpossibleFX Player and how to use render URLs with popular third-party players.


ImpossibleFX Player

The ImpossibleFX Player (FXPlayer) is a built-in HTML5 video player that handles rendering and playback in a single step. It streams via HLS using hls.js and includes custom controls, keyboard shortcuts, fullscreen support, and CTA overlays.

Authentication

There are two ways to use the player with ImpossibleFX rendering:

Token-based (recommended) — Your server makes the render request and obtains a token. The player then uses that token to stream the video. No API key is needed on the client — tokens do not require additional authentication. Pass the token as src and the player auto-detects it:

const player = new FXPlayer("player", {
  src: "v2:eu-west-1:abc123-def456-789",
  controls: true,
});

By default this streams via HLS. To play as MP4 instead, set format:

const player = new FXPlayer("player", {
  src: "v2:eu-west-1:abc123-def456-789",
  format: "mp4",
  controls: true,
});

Direct rendering — The player calls the render backend directly from the browser using the impossible config. This is simpler but means the projectId is exposed in client-side code. By default, projects allow unauthenticated rendering, so this works without an API key:

const player = new FXPlayer("player", {
  impossible: {
    projectId: "YOUR-PROJECT-ID",
    movie: "welcome-video",
    params: { name: "Alex" },
  },
});
player.play();

If your project is configured to require authentication, you must also provide an apiKey:

const player = new FXPlayer("player", {
  impossible: {
    projectId: "YOUR-PROJECT-ID",
    movie: "welcome-video",
    apiKey: "YOUR-API-KEY",
    params: { name: "Alex" },
  },
});
! Warning

If the player calls the render backend directly and your project requires authentication, create a dedicated API key for this purpose so it can be revoked independently without affecting other integrations. For maximum security, use the token-based approach instead — your server handles authentication and the client never sees any credentials.

Quick setup

Include the player CSS and script, then create a player with your project details:

<link rel="stylesheet" href="https://cdn.impossible.io/fxplayer/v3/fxplayer.css" />
<script src="https://cdn.impossible.io/fxplayer/v3/fxplayer.js"></script>

<div id="player" style="width: 640px; height: 360px;"></div>

<script>
  const player = new fxplayer.FXPlayer("player", {
    impossible: {
      projectId: "YOUR-PROJECT-ID",
      movie: "welcome-video",
      params: {
        name: "Alex",
        company: "Acme Inc",
      },
    },
  });
  player.play();
</script>

The player makes the render request, streams the video via HLS, and starts playback automatically.

Installation

<link rel="stylesheet" href="https://cdn.impossible.io/fxplayer/v3/fxplayer.css" />
<script src="https://cdn.impossible.io/fxplayer/v3/fxplayer.js"></script>

No build step needed. The script adds fxplayer.FXPlayer to the global scope.

npm install fxplayer

Then import in your code:

import { FXPlayer } from "fxplayer";
import "fxplayer/dist/fxplayer.css";

Creating a player

// Pass the ID of a container element
const player = new FXPlayer("player", options);

// Or pass the element directly
const el = document.getElementById("player");
const player = new FXPlayer(el, options);

The player creates a <video> element inside the container you provide.

Options

Parameter Type Required Default Description
src String No Video source URL or a render token (e.g. "v2:eu-west-1:abc123"). Tokens are auto-detected and resolved to a render URL using the format option.
format String No "auto" Video format: "hls", "mp4", or "auto". Auto-detects from URL extension. When using a render token as src, this determines the output format (defaults to HLS).
controls Boolean No true Show player controls.
autoplay Boolean No false Auto-play when loaded.
muted Boolean No false Start muted.
poster String No Poster image URL shown before playback.
loop Boolean No false Loop video on end.
keyboard Boolean No true Enable keyboard shortcuts (Space, arrows, F for fullscreen, M for mute).
debug Boolean No false Enable debug logging to the console.
accentColor String No CSS color for the player UI accent (progress bar, playhead, volume).
contextMenu Boolean | Object No Context menu behavior. false disables it entirely (blocks Save Video, PiP, etc.). true replaces the native menu with a custom one. An object like { playPause: true, loop: true } shows only specific items.

Impossible.io rendering options

Pass these inside the impossible object to configure server-side rendering:

Parameter Type Required Default Description
impossible.projectId String Yes Your project's UUID.
impossible.movie String Yes The name of the dynamic movie to render.
impossible.params Object No {} Key-value pairs for the movie's dynamic variables.
impossible.region String No Render region (e.g. "eu-west-1", "us-east-1"). Defaults to the global endpoint.
impossible.parallel Number No 1 Number of parallel render servers. Higher values render faster.
impossible.routingKey String No "default" Routing key for dedicated render clusters.
impossible.apiKey String No API key for server-side authentication. Grants access to all projects — do not use in client-side code.
impossible.isToken String No Alternative authentication token (istoken). Use when your backend issues scoped session tokens.

Methods

MethodDescription
play()Starts rendering (if needed) and playback.
pause()Pauses playback.
stop()Stops playback and resets to the beginning.
seek(seconds)Seeks to a specific time in seconds.
setSrc(url, format?)Sets a video source URL or render token. Auto-detects HLS vs MP4. Tokens (e.g. "v2:...") are resolved automatically.
setMovie(projectId, movie)Configures project and movie for rendering.
setParams(params)Sets dynamic rendering parameters.
setToken(token)Sets a pre-obtained render token directly.
enterFullscreen()Enters fullscreen mode.
exitFullscreen()Exits fullscreen mode.
toggleFullscreen()Toggles fullscreen mode.
setPosterUrl(url)Sets a custom poster image from a URL. Returns a promise.
addSubtitleTrack(track)Dynamically adds a subtitle track. See Subtitles.
destroy()Cleans up all resources and event listeners.

Properties

PropertyTypeDescription
currentTimeNumberCurrent playback position in seconds (read-only).
durationNumberTotal video duration in seconds (read-only).
playingBooleanWhether the video is currently playing (read-only).
volumeNumberVolume level from 0 to 1 (read/write).
mutedBooleanWhether the video is muted (read/write).
fullscreenBooleanWhether the player is in fullscreen (read-only).

Events

Listen to player events with on() and off():

player.on("ready", () => console.log("Video ready"));
player.on("timeupdate", ({ time, duration }) => {
  console.log(`${time}s / ${duration}s`);
});
player.on("error", ({ message }) => console.error(message));
EventDataDescription
readyVideo is ready to play.
playPlayback started.
pausePlayback paused.
endedVideo finished.
timeupdate{ time, duration }Fires during playback with current position.
volumechange{ volume, muted }Volume or mute state changed.
fullscreenchange{ fullscreen }Fullscreen state changed.
error{ message, code? }A playback error occurred.

Token-based playback

If you’ve already made a render request and have a token, pass it as src:

// HLS streaming (default)
const player = new FXPlayer("player", {
  src: "v2:eu-west-1:abc123-def456-789",
  controls: true,
});

// MP4 playback
const player = new FXPlayer("player", {
  src: "v2:eu-west-1:abc123-def456-789",
  format: "mp4",
  controls: true,
});

You can also set the token programmatically:

const player = new FXPlayer("player", { controls: true });
player.setToken("v2:eu-west-1:abc123-def456-789");
player.play();

Dynamic configuration

You can also configure the project and parameters after creating the player:

const player = new FXPlayer("player");
player.setMovie("YOUR-PROJECT-ID", "welcome-video");
player.setParams({ name: "Alex", company: "Acme Inc" });
player.play();

CTA overlays

The player supports Call-To-Action overlays that appear during or after playback. Use them for promotions, subscribe prompts, or end screens.

player.addCTA("promo", {
  content: '<div class="promo">50% off — use code SAVE50</div>',
  startTime: 5,
  endTime: 12,
  position: "center",
  dismissible: true,
});

CTA options

Parameter Type Required Default Description
content String | HTMLElement Yes HTML string or DOM element to display inside the overlay.
startTime Number No When to show the CTA (in seconds). Omit for an end-screen CTA that appears when the video finishes.
endTime Number No When to hide the CTA (in seconds). Omit to keep it visible until dismissed.
position String No "center" Overlay position: "center", "top", or "bottom".
dismissible Boolean No true Show a close button so the viewer can dismiss the CTA.
pauseOnShow Boolean No false Pause the video when this CTA is shown.
className String No Custom CSS class to add to the overlay element.

CTA methods

MethodDescription
addCTA(id, options)Registers a CTA overlay.
removeCTA(id)Removes a CTA by its ID.
showCTA(id)Manually shows a CTA.
hideCTA(id)Manually hides a CTA.

CTA events

EventDataDescription
cta:show{ id }A CTA overlay became visible.
cta:hide{ id }A CTA overlay was hidden.
cta:click{ id }The viewer clicked a CTA.

CTA patterns

Timed promo — visible between 5s and 12s:

player.addCTA("promo", {
  content: '<div class="banner">Limited offer!</div>',
  startTime: 5,
  endTime: 12,
  position: "center",
});

Persistent pill — appears at 3s, stays until dismissed:

player.addCTA("subscribe", {
  content: '<div class="pill">Subscribe</div>',
  startTime: 3,
  position: "bottom",
  dismissible: true,
});

End screen — shown when the video finishes, pauses playback:

player.addCTA("end-screen", {
  content: '<div class="end">Thanks for watching! <button>Sign up</button></div>',
  position: "center",
  pauseOnShow: true,
  dismissible: false,
});

Subtitles

New in 3.3.0

The player supports WebVTT subtitles with a built-in settings panel for font size, color, background, and position. Settings are persisted in localStorage.

Basic usage

const player = new FXPlayer("player", {
  src: "https://example.com/video.mp4",
  subtitles: {
    tracks: [
      { src: "english.vtt", srclang: "en", label: "English" },
      { src: "spanish.vtt", srclang: "es", label: "Español" },
    ],
  },
});

Subtitle options

Pass these inside the subtitles object:

Parameter Type Required Default Description
subtitles.tracks SubtitleTrack[] No [] Array of subtitle tracks. Each track has src (VTT URL), srclang (language code), and label (display name).
subtitles.storageKey String No "fxplayer" Custom localStorage key prefix for persisting subtitle settings (font size, colors, position).

SubtitleTrack

Each track object has:

PropertyTypeDescription
srcStringURL to a WebVTT (.vtt) file.
srclangStringLanguage code (e.g. “en”, “es”, “de”).
labelStringDisplay name shown in the track selector (e.g. “English”).

Adding tracks dynamically

player.addSubtitleTrack({
  src: "https://example.com/french.vtt",
  srclang: "fr",
  label: "Français",
});

Settings panel

When subtitles are configured, the player shows a CC button and a settings (gear) button in the control bar. The settings panel lets viewers customize:

  • Track — choose between available subtitle tracks or turn them off
  • Font size — 50% to 200%
  • Font color — White, Yellow, Cyan, Green
  • Background — Black (75%, 50%, 25% opacity) or transparent
  • Position — Bottom or Top

All settings are saved to localStorage and restored on next visit.

Impossible.io integration

When using the player with Impossible.io rendering, subtitle VTT files can be lazily loaded — the player fetches the VTT URL only when the viewer enables subtitles.

const player = new FXPlayer("player", {
  impossible: {
    projectId: "YOUR-PROJECT-ID",
    movie: "welcome-video",
    params: { name: "Alex" },
  },
  subtitles: {
    tracks: [
      { src: "auto", srclang: "en", label: "English" },
    ],
  },
});

Poster images

Set a custom poster image from any URL:

const player = new FXPlayer("player", {
  src: "https://example.com/video.mp4",
});

// Set poster from a URL
await player.setPosterUrl("https://example.com/poster.jpg");

This works alongside the static poster option — use poster for a known URL at construction time, and setPosterUrl() when the poster URL is determined later.

Examples

* Tip

The player uses HLS streaming by default via hls.js. HLS is supported natively on Safari and iOS; on Chrome, Firefox, and Edge the bundled hls.js polyfill handles playback automatically.

JW Player

JW Player is a widely-used commercial video player with HLS support, analytics, and ad integrations.

Using a token-based URL:

<div id="player"></div>

<script src="https://cdn.jwplayer.com/libraries/YOUR-PLAYER-KEY.js"></script>
<script>
  const token = "v2:eu-west-1:abc123-def456-789";

  jwplayer("player").setup({
    sources: [
      {
        file: `https://render.impossible.io/v2/render/${token}.m3u8`,
        type: "hls",
      },
    ],
    width: 640,
    height: 360,
  });
</script>

You can also use a direct URL instead of tokens — just pass the v1 render URL as the file source.

* Tip

JW Player has native HLS support, so use .m3u8 for adaptive bitrate streaming. For a simple setup, .mp4 works across all configurations.

Video.js

Video.js is the most popular open-source HTML5 video player, with a large plugin ecosystem and full HLS/DASH support.

Using a token-based URL:

<link href="https://vjs.zencdn.net/8.10.0/video-js.css" rel="stylesheet" />
<script src="https://vjs.zencdn.net/8.10.0/video.min.js"></script>

<video
  id="my-video"
  class="video-js"
  controls
  width="640"
  height="360"
>
</video>

<script>
  const token = "v2:eu-west-1:abc123-def456-789";

  const player = videojs("my-video", {
    sources: [
      {
        src: `https://render.impossible.io/v2/render/${token}.mp4`,
        type: "video/mp4",
      },
    ],
  });
</script>

You can also use a direct URL as the source — just pass the v1 render URL in the <source> tag.

HLS streaming with Video.js:

Video.js includes HLS support via its built-in VHS (Video.js HTTP Streaming) library:

const token = "v2:eu-west-1:abc123-def456-789";

const player = videojs("my-video", {
  sources: [
    {
      src: `https://render.impossible.io/v2/get/${token}.m3u8`,
      type: "application/x-mpegURL",
    },
  ],
});

Wistia

Wistia is a video platform focused on marketing and analytics. You can embed external video URLs using Wistia’s iframe embed or their Player API.

Using a token-based URL with an iframe:

<iframe
  src="https://fast.wistia.net/embed/iframe/WISTIA-VIDEO-ID"
  width="640"
  height="360"
  allowfullscreen
></iframe>

To use ImpossibleFX videos with Wistia, upload the rendered video via the Wistia Upload API:

# 1. Render the video
TOKEN=$(curl -s -X POST https://render.impossible.io/v2/render/YOUR-PROJECT-ID \
  -H "Content-Type: application/json" \
  -d '{"movie": "welcome-video", "params": {"name": "Alex"}}' \
  | jq -r '.token')

# 2. Upload the render URL to Wistia
curl -X POST "https://upload.wistia.com/api/v1/medias" \
  -H "Authorization: Bearer YOUR-WISTIA-API-TOKEN" \
  -d "url=https://render.impossible.io/v2/render/${TOKEN}.mp4"

Wistia will fetch the video from the render URL and host it on their platform, giving you access to their analytics, heatmaps, and embed tools. You can also pass a direct URL instead of the token-based URL.

Vimeo

Vimeo is a professional video hosting platform. Since Vimeo’s player only plays Vimeo-hosted content, the integration involves uploading your rendered video to Vimeo, then embedding it with their player.

Upload via the Vimeo API:

# 1. Render the video
TOKEN=$(curl -s -X POST https://render.impossible.io/v2/render/YOUR-PROJECT-ID \
  -H "Content-Type: application/json" \
  -d '{"movie": "welcome-video", "params": {"name": "Alex"}}' \
  | jq -r '.token')

# 2. Create a video on Vimeo with a pull URL
curl -X POST "https://api.vimeo.com/me/videos" \
  -H "Authorization: Bearer YOUR-VIMEO-ACCESS-TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"upload\": {
      \"approach\": \"pull\",
      \"link\": \"https://render.impossible.io/v2/render/${TOKEN}.mp4\"
    },
    \"name\": \"Personalized Video for Alex\"
  }"

Vimeo will pull the rendered video from the ImpossibleFX URL and host it. The response includes the Vimeo video URI which you can use to build an embed:

<iframe
  src="https://player.vimeo.com/video/VIMEO-VIDEO-ID"
  width="640"
  height="360"
  frameborder="0"
  allowfullscreen
></iframe>

You can also pass a direct URL as the link value instead of the token-based URL.

i Note

For high-volume Vimeo uploads, consider using ImpossibleFX’s built-in upload destinations to send rendered videos directly to cloud storage, then pull from there into Vimeo.