The ČSFD API library works perfectly in browser extensions, enabling you to add ČSFD ratings and information to other streaming platforms and websites. This guide covers setup, CORS handling, and real-world examples.
Why Use in Browser Extensions?
Browser extensions can enhance streaming platforms by:
Displaying ratings - Show ČSFD ratings on Netflix, HBO, etc.
Adding metadata - Display Czech reviews, cast info, and more
Enriching catalogs - Augment film databases with ČSFD data
Creating tools - Build custom movie discovery features
The library is already being used in production extensions with thousands of users. See the Real-World Examples section.
Real-World Examples
These extensions are built with node-csfd-api and are available in production:
Netflix ČSFD Extension
What it does : Shows ČSFD ratings directly on Netflix
Features :
Display ČSFD rating badge on Netflix thumbnails
Link directly to ČSFD film pages
Works on Netflix browse and watch pages
Links :
Tech Stack : TypeScript, Manifest V3, node-csfd-api
Dafilms Extension
What it does : Integrates ČSFD ratings into Dafilms.cz
Features :
Show ČSFD ratings on Dafilms catalog
Quick links to full ČSFD pages
Real-time rating updates
Links :
Kviff.tv Extension
What it does : Adds ČSFD integration to Kviff.tv festival platform
Features :
Festival film ratings
Director and cast information
Enhanced film discovery
Links :
Setup Guide
Installation
Install the package in your extension project:
npm install node-csfd-api
Manifest Configuration
{
"manifest_version" : 3 ,
"name" : "My ČSFD Extension" ,
"version" : "1.0.0" ,
"description" : "Show ČSFD ratings" ,
"permissions" : [
"activeTab"
],
"host_permissions" : [
"https://www.csfd.cz/*"
],
"content_scripts" : [{
"matches" : [ "https://www.netflix.com/*" ],
"js" : [ "content.js" ]
}],
"background" : {
"service_worker" : "background.js"
}
}
{
"manifest_version" : 2 ,
"name" : "My ČSFD Extension" ,
"version" : "1.0.0" ,
"description" : "Show ČSFD ratings" ,
"permissions" : [
"https://www.csfd.cz/*" ,
"activeTab"
],
"content_scripts" : [{
"matches" : [ "https://www.netflix.com/*" ],
"js" : [ "content.js" ]
}],
"background" : {
"scripts" : [ "background.js" ]
}
}
Important Permissions :
host_permissions (V3) or permissions (V2) must include https://www.csfd.cz/*
This allows the extension to fetch data from ČSFD
CORS Considerations
Browser extensions need special handling for Cross-Origin Resource Sharing (CORS).
Why CORS Matters
Problem : Web pages cannot directly fetch from ČSFD due to CORS restrictions.
Solution : Browser extensions can bypass CORS with proper permissions.
Declare host permissions
"host_permissions" : [ "https://www.csfd.cz/*" ]
Fetch in background script
Background scripts/service workers can access ČSFD without CORS issues.
Use message passing
Content scripts send messages to background script to fetch data.
Architecture Pattern
Content Script → Message → Background Script → ČSFD API → Response
(Netflix) (node-csfd-api) (Data)
Example: Netflix ČSFD Extension
Here’s a simplified version of how the Netflix ČSFD extension works:
Content Script
// Runs on Netflix pages
import { chrome } from 'chrome' ;
// Find all movie titles on the page
const movieTitles = document . querySelectorAll ( '.movie-title' );
movieTitles . forEach ( async ( element ) => {
const title = element . textContent ;
// Send message to background script
const response = await chrome . runtime . sendMessage ({
action: 'searchMovie' ,
title: title
});
if ( response . movie ) {
// Display ČSFD rating
displayRating ( element , response . movie );
}
});
function displayRating ( element : Element , movie : any ) {
const badge = document . createElement ( 'div' );
badge . className = 'csfd-rating-badge' ;
badge . innerHTML = `
<a href=" ${ movie . url } " target="_blank">
ČSFD: ${ movie . rating } %
</a>
` ;
element . appendChild ( badge );
}
Background Script
// Service worker (Manifest V3)
import { csfd } from 'node-csfd-api' ;
// Listen for messages from content scripts
chrome . runtime . onMessage . addListener (( request , sender , sendResponse ) => {
if ( request . action === 'searchMovie' ) {
searchMovie ( request . title )
. then ( movie => sendResponse ({ movie }))
. catch ( error => sendResponse ({ error: error . message }));
// Return true to indicate async response
return true ;
}
});
async function searchMovie ( title : string ) {
try {
// Search ČSFD
const results = await csfd . search ( title );
if ( results . movies . length > 0 ) {
const movie = results . movies [ 0 ];
// Get full movie details
const details = await csfd . movie ( movie . id );
return details ;
}
return null ;
} catch ( error ) {
console . error ( 'ČSFD search error:' , error );
return null ;
}
}
Styling
.csfd-rating-badge {
display : inline-block ;
padding : 4 px 8 px ;
background : #ba0305 ;
color : white ;
border-radius : 4 px ;
font-size : 12 px ;
margin-left : 8 px ;
}
.csfd-rating-badge a {
color : white ;
text-decoration : none ;
}
.csfd-rating-badge a :hover {
text-decoration : underline ;
}
Complete Example Project
Here’s a complete minimal extension structure:
my-csfd-extension/
├── manifest.json
├── background.ts
├── content.ts
├── content.css
├── package.json
└── tsconfig.json
package.json
{
"name" : "my-csfd-extension" ,
"version" : "1.0.0" ,
"type" : "module" ,
"scripts" : {
"build" : "tsc && vite build" ,
"dev" : "vite build --watch"
},
"dependencies" : {
"node-csfd-api" : "latest"
},
"devDependencies" : {
"@types/chrome" : "^0.0.268" ,
"typescript" : "^5.0.0" ,
"vite" : "^5.0.0"
}
}
Build Configuration
import { defineConfig } from 'vite' ;
import { resolve } from 'path' ;
export default defineConfig ({
build: {
rollupOptions: {
input: {
background: resolve ( __dirname , 'background.ts' ),
content: resolve ( __dirname , 'content.ts' )
},
output: {
entryFileNames: '[name].js' ,
format: 'iife'
}
}
}
}) ;
Advanced Features
Caching Results
Cache API responses to improve performance:
import { csfd } from 'node-csfd-api' ;
// Simple in-memory cache
const cache = new Map < string , any >();
const CACHE_DURATION = 1000 * 60 * 60 ; // 1 hour
async function searchMovieWithCache ( title : string ) {
// Check cache
const cached = cache . get ( title );
if ( cached && Date . now () - cached . timestamp < CACHE_DURATION ) {
return cached . data ;
}
// Fetch from API
const results = await csfd . search ( title );
// Store in cache
cache . set ( title , {
data: results ,
timestamp: Date . now ()
});
return results ;
}
Persistent Storage
Use Chrome storage API for persistent caching:
import { csfd } from 'node-csfd-api' ;
async function getMovieWithStorage ( movieId : number ) {
// Try to get from storage
const result = await chrome . storage . local . get ([ `movie_ ${ movieId } ` ]);
if ( result [ `movie_ ${ movieId } ` ]) {
return result [ `movie_ ${ movieId } ` ];
}
// Fetch from API
const movie = await csfd . movie ( movieId );
// Save to storage
await chrome . storage . local . set ({
[ `movie_ ${ movieId } ` ]: movie
});
return movie ;
}
Rate Limiting
Implement rate limiting to avoid overwhelming ČSFD:
class RateLimiter {
private queue : Array <() => Promise < any >> = [];
private processing = false ;
private delay = 1000 ; // 1 second between requests
async add < T >( fn : () => Promise < T >) : Promise < T > {
return new Promise (( resolve , reject ) => {
this . queue . push ( async () => {
try {
const result = await fn ();
resolve ( result );
} catch ( error ) {
reject ( error );
}
});
this . process ();
});
}
private async process () {
if ( this . processing || this . queue . length === 0 ) return ;
this . processing = true ;
while ( this . queue . length > 0 ) {
const task = this . queue . shift ();
if ( task ) {
await task ();
await new Promise ( resolve => setTimeout ( resolve , this . delay ));
}
}
this . processing = false ;
}
}
// Usage
const limiter = new RateLimiter ();
async function searchWithRateLimit ( title : string ) {
return limiter . add (() => csfd . search ( title ));
}
Testing Your Extension
Load in Chrome
Go to chrome://extensions
Enable “Developer mode”
Click “Load unpacked”
Select your extension directory
Test on target site
Navigate to Netflix (or your target site) and verify the extension works.
Check console for errors
Open DevTools and check for any errors in both:
Page console (content script)
Extension background page console
Best Practices
Cache aggressively - ČSFD data doesn’t change frequently
Debounce searches - Wait for user to finish typing
Lazy load - Only fetch data when needed (on hover, click, etc.)
Batch requests - Combine multiple searches when possible
User Experience
Show loading states - Display spinner while fetching
Handle errors gracefully - Don’t break the page if API fails
Provide fallbacks - Work even if ČSFD is unreachable
Respect user preferences - Allow users to disable features
Security
Sanitize data - Never inject raw HTML from API responses
Validate inputs - Check movie titles before searching
Use CSP - Configure Content Security Policy in manifest
Minimize permissions - Only request what you need
{
"content_security_policy" : {
"extension_pages" : "script-src 'self'; object-src 'self'"
}
}
Troubleshooting
Extension doesn’t load
Check :
Manifest JSON is valid
All required files exist
No syntax errors in scripts
CORS errors
Solution :
Ensure host_permissions includes ČSFD domain
Fetch in background script, not content script
No data showing
Debug :
// Add logging
console . log ( 'Searching for:' , title );
const results = await csfd . search ( title );
console . log ( 'Results:' , results );
Rate limited by ČSFD
Solution :
Implement caching
Add delays between requests
Use rate limiting queue
Publishing Your Extension
Chrome Web Store
Firefox Add-ons
Create developer account at Chrome Web Store
Pay $5 one-time registration fee
Prepare assets:
Icon (128x128, 48x48, 16x16)
Screenshots
Description
Upload ZIP of extension
Submit for review
Create account at Firefox Add-ons
Prepare assets:
Icon (128x128, 48x48)
Screenshots
Description
Upload XPI file
Submit for review
Important : Make it clear in your extension description that this is an unofficial tool and not affiliated with ČSFD.cz.
See Also
Netflix ČSFD Extension Full source code of production extension
Chrome Extension Docs Official Chrome extension documentation
API Reference Complete ČSFD API reference
Basic Usage Learn the API basics