ProductsServicesDocsPricingAboutContact Log in Sign up

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.

This page covers how to get a render URL and use it with popular third-party players.

Getting a render URL

There are two ways to get a playable video URL from ImpossibleFX.

First, make a render request to get a token:

curl -X POST https://render.impossible.io/v2/render/YOUR-PROJECT-ID \
  -H "Content-Type: application/json" \
  -d '{"movie": "welcome-video", "params": {"name": "Alex"}}'

The API returns a token:

{ "token": "v2:eu-west-1:abc123-def456-789" }

Build the video URL using the token and your desired format:

FormatURL
MP4https://render.impossible.io/v2/render/{token}.mp4
HLShttps://render.impossible.io/v2/render/{token}.m3u8
DASHhttps://render.impossible.io/v2/render/{token}.mpd
WebMhttps://render.impossible.io/v2/render/{token}.webm

You can also use different retrieval modesrender (full render first), get (progressive download), or play (stream immediately).

Direct URL

For simpler use cases, render and retrieve in a single URL with no token step:

https://render.impossible.io/v1/render/YOUR-PROJECT-ID/welcome-video.mp4?name=Alex&company=Acme

Pass dynamic parameters as query strings. This is useful for email campaigns, CRM templates, or anywhere you need a single self-contained URL.

* Tip

Token-based URLs give you more control — you can choose retrieval modes, use HLS/DASH streaming, and reuse tokens. Direct URLs are simpler and work anywhere a static URL is expected.


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.

Quick setup

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

<link rel="stylesheet" href="https://cdn.impossible.io/support/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/support/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. Not needed when using the impossible config.
format String No "auto" Video format: "hls", "mp4", or "auto". Auto-detects from URL extension.
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.

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.

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 directly. Auto-detects HLS vs MP4.
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.
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, you can skip the project/movie/params setup:

const player = new FXPlayer("player");
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,
});

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>

Using a direct URL:

<script>
  jwplayer("player").setup({
    file: "https://render.impossible.io/v1/render/YOUR-PROJECT-ID/welcome-video.mp4?name=Alex",
    width: 640,
    height: 360,
  });
</script>
* 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>

Using a direct URL:

<video
  id="my-video"
  class="video-js"
  controls
  width="640"
  height="360"
>
  <source
    src="https://render.impossible.io/v1/render/YOUR-PROJECT-ID/welcome-video.mp4?name=Alex"
    type="video/mp4"
  />
</video>

<script>
  const player = videojs("my-video");
</script>

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.

Using a direct URL:

curl -X POST "https://upload.wistia.com/api/v1/medias" \
  -H "Authorization: Bearer YOUR-WISTIA-API-TOKEN" \
  -d "url=https://render.impossible.io/v1/render/YOUR-PROJECT-ID/welcome-video.mp4?name=Alex"

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>

Using a direct 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/v1/render/YOUR-PROJECT-ID/welcome-video.mp4?name=Alex"
    },
    "name": "Personalized Video for Alex"
  }'
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.