The XAPlayer secure player with Node.js and Express
Get a playback token on your Node.js server with fetch and show the XAPlayer secure player on an Express lesson page.
All guides
Start
Quick start: your first protected course in 10 minutesVideo security: encryption, watermarks and what no player can doAdd to your site
Embed the secure player in WordPressSell video courses with WooCommerce and the secure playerThe XAPlayer secure player in MoodleThe XAPlayer secure player in LaravelThe XAPlayer secure player with Node.js and ExpressThe XAPlayer secure player in Next.jsThe XAPlayer secure player with Python: Django and FlaskHTML sites, site builders, or no serverFor sellers
Uploading videos and automatic protectionIssuing licenses, device limits and bulk issuingHow to stop IDM and downloaders from saving your course videosProtect course videos on WordPress and WooCommerceFor students
For students: watching a course with a license codePlatforms: Android, iPhone, Windows, Mac and LinuxWatching a course on AndroidWatching a course on iPhone and iPadWatching a course on Windows, Mac and LinuxFor developers
API reference: embed the secure player on any siteYou’ll write a small function that gets a playback token for the signed-in user, and an Express route that shows the player. Node.js 18 and later include fetch, so no extra package is needed.
Before you start#
- In your XAPlayer panel, open Settings and create an API key. It is shown only once, so copy it right away.
- Under Websites allowed to show your player, add your site’s full address, such as https://academy.example.com. If your site also opens with www, add that too.
- Get the course ID: in Settings, pick the course in “Show the player on your website” and the ID is filled into the sample code. It is also the last part of the course page’s address in the panel.
# .env (or your host's environment settings)
XAPLAYER_API_KEY=xap_sk_...
The token function#
// xaplayer.js (Node 18 or later: fetch is built in)
const XAPLAYER = 'https://en.xaplayer.ir/api/v1';
export async function playerUrl({ courseId, videoId, user }) {
const res = await fetch(`${XAPLAYER}/embed-tokens`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.XAPLAYER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
...(videoId ? { videoId } : { courseId }),
viewer: { id: String(user.id), name: user.name },
}),
});
if (!res.ok) throw new Error(`XAPlayer ${res.status}: ${await res.text()}`);
const { url } = await res.json();
return url;
}
The lesson route#
// server.js
import express from 'express';
import { playerUrl } from './xaplayer.js';
const app = express();
// requireLogin and userBoughtCourse are your own: your sign-in and your orders.
app.get('/courses/:courseId/watch', requireLogin, async (req, res, next) => {
try {
if (!(await userBoughtCourse(req.user, req.params.courseId))) return res.sendStatus(403);
const url = await playerUrl({ courseId: req.params.courseId, user: req.user });
res.render('watch', { url }); // or any template engine you use
} catch (err) {
next(err);
}
});
If it doesn’t work#
| What you see | Cause and fix |
|---|---|
| The player area is empty or the browser says it refused to connect | Your site isn’t in the allowed websites, or www differs. Add the page’s exact address. |
| 401 unauthorized | The API key is wrong, or you created a new key and the old one stopped working. Copy the key again. |
| 404 not_found | The course or video ID is wrong or belongs to another account. |
| 400 bad_request | The body is incomplete: send exactly one of courseId or videoId, and a non-empty viewer.id. |
| After a few hours the player says the page timed out | The token expired. Get a fresh token every time the page opens, and never cache the player address. |
Try XAPlayer free for 14 days, with 10 licenses on us.
Try it free with your own course