Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The maintainable way to collect IMDb movie ratings and metadata in Node.js is to use IMDb’s permitted data products rather than scrape the public website. For non-commercial batch work, stream the daily gzipped TSV datasets from datasets.imdbws.com and join title.basics with title.ratings on tconst. For licensed, current lookups, use IMDb’s GraphQL product through AWS Data Exchange. Use Cheerio or Puppeteer only when you have express written permission to fetch the page.

Choose the right IMDb data source first

There are four technically different approaches. Your choice affects freshness, licensing, cost, and how much code you must maintain.

Approach Best for Freshness Operational trade-off
IMDb bulk TSV datasets Permitted non-commercial imports, analytics, local catalogs Files are refreshed daily Download and stream large files; join tables locally
IMDb GraphQL API through AWS Data Exchange Licensed applications needing search or current fields Real-time product Requires an AWS account, credentials, and a product subscription; check the subscribed product’s current price, limits, retention, and redistribution terms
Cheerio Authorized HTML or embedded-data parsing As fresh as the fetched page Parses received markup but does not run JavaScript
Puppeteer or Playwright Authorized pages whose fields are rendered client-side As fresh as the browser session Higher CPU, memory, and failure surface than a parser

Why permission matters

IMDb’s help guidance says: “The data must be taken only from the datasets made available (see IMDb Contributor Datasets).” Website data mining, robots, screen scraping, or similar extraction requires express written consent. Do not bypass robots rules, CAPTCHAs, bot checks, rate limits, or other controls. The examples below use the official datasets or assume that you already have written authorization for page access.

What the IMDb datasets contain

The bulk files are gzipped, UTF-8, tab-separated files. IMDb documents their schemas and refreshes them daily at datasets.imdbws.com. Keep every identifier as a string: tconst values such as tt0111161 are alphanumeric.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
File Useful fields Typical join
title.basics.tsv.gz tconst, titleType, primaryTitle, originalTitle, isAdult, startYear, endYear, runtimeMinutes, genres Join to ratings and optional title tables on tconst
title.ratings.tsv.gz tconst, averageRating, numVotes Join to title.basics
title.crew.tsv.gz Directors and writers Left-join on tconst
title.principals.tsv.gz Principal cast and crew Left-join on tconst, then resolve names through name.basics.tsv.gz
title.episode.tsv.gz Series episode relationships Use when the title is an episode rather than a standalone movie
title.akas.tsv.gz Alternative titles and regions Join on tconst

A missing value is represented by N, not zero. Convert it to null before converting numbers. Ratings are snapshots: store the time you fetched them and the dataset date so later imports can be compared.

Stream a movie-and-rating join in Node.js

Streaming avoids loading multi-gigabyte files into memory. The following Node.js 18+ script accepts one or more IMDb title IDs, reads only those rows, converts types, and joins basics with ratings. It uses only built-in modules.

Run it

  1. Install Node.js 18 or newer.
  2. Save the code as imdb-movies.mjs.
  3. Run node imdb-movies.mjs tt0111161 tt0133093.
  4. Persist the JSON output together with retrieved_at and your dataset revision or retrieval date.
import https from 'node:https';
import zlib from 'node:zlib';
import readline from 'node:readline';

const NULL = '\N';

function value(raw) {
  return raw === NULL ? null : raw;
}

function numberOrNull(raw, parser) {
  const v = value(raw);
  if (v === null || v === '') return null;
  const n = parser(v);
  return Number.isFinite(n) ? n : null;
}

function streamTsv(url, onRow) {
  return new Promise((resolve, reject) => {
    const request = https.get(url, response => {
      if (response.statusCode !== 200) {
        response.resume();
        reject(new Error(`${url} returned HTTP ${response.statusCode}`));
        return;
      }
      const input = response.pipe(zlib.createGunzip());
      const lines = readline.createInterface({ input, crlfDelay: Infinity });
      let headers;
      lines.on('line', line => {
        if (!headers) {
          headers = line.split('t');
          return;
        }
        const cells = line.split('t');
        const row = Object.fromEntries(headers.map((h, i) => [h, cells[i] ?? NULL]));
        onRow(row);
      });
      lines.on('close', resolve);
      input.on('error', reject);
    });
    request.on('error', reject);
  });
}

const wanted = new Set(process.argv.slice(2));
if (wanted.size === 0) {
  console.error('Usage: node imdb-movies.mjs tt0111161 [tt0133093 ...]');
  process.exit(1);
}

const basics = new Map();
await streamTsv('https://datasets.imdbws.com/title.basics.tsv.gz', row => {
  if (!wanted.has(row.tconst)) return;
  if (row.titleType !== 'movie') return;
  basics.set(row.tconst, {
    tconst: row.tconst,
    titleType: row.titleType,
    primaryTitle: value(row.primaryTitle),
    originalTitle: value(row.originalTitle),
    isAdult: value(row.isAdult) === null ? null : value(row.isAdult) === '1',
    startYear: numberOrNull(row.startYear, Number),
    endYear: numberOrNull(row.endYear, Number),
    runtimeMinutes: numberOrNull(row.runtimeMinutes, Number),
    genres: value(row.genres)?.split(',').filter(Boolean) ?? null
  });
});

await streamTsv('https://datasets.imdbws.com/title.ratings.tsv.gz', row => {
  const movie = basics.get(row.tconst);
  if (!movie) return;
  movie.rating = numberOrNull(row.averageRating, Number);
  movie.numVotes = numberOrNull(row.numVotes, Number);
});

const result = {
  retrieved_at: new Date().toISOString(),
  movies: [...basics.values()]
};
console.log(JSON.stringify(result, null, 2));

This example deliberately scans each source file while retaining only requested IDs. For a full catalog, write rows incrementally to a database or columnar files instead of keeping a map in memory. Keep the original row or a checksum if you need an audit trail. Do not turn absent years, runtimes, genres, or ratings into zeroes.

Add crew, cast, and alternative titles

Use the same streaming function for title.crew, title.principals, title.akas, and name.basics. Build a left join keyed by tconst; principal rows reference nconst, which you resolve against name.basics. Keep arrays for multiple directors, writers, cast members, and regional titles. Check titleType before presenting a record as a movie, because the datasets also contain series, episodes, shorts, videos, and other title types.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Use the licensed GraphQL API for real-time lookups

IMDb describes its GraphQL API on AWS Data Exchange as a real-time, field-selective option with title and name search, ratings, metadata, and cast information. Access requires an AWS account, credentials, and a subscription to the product. Authentication details and limits are product-specific, so read the current terms of the subscription rather than copying credentials into source code.

The request shape below is a Node.js pattern. Set IMDB_GRAPHQL_ENDPOINT to the endpoint supplied with your subscription and put the complete authorization value required by that product in IMDB_AUTHORIZATION.

const query = `
  query Movie($id: ID!) {
    title(id: $id) {
      id
      titleText { text }
      releaseYear { year }
      runtime { seconds }
      ratingsSummary { aggregateRating voteCount }
    }
  }
`;

const response = await fetch(process.env.IMDB_GRAPHQL_ENDPOINT, {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'authorization': process.env.IMDB_AUTHORIZATION
  },
  body: JSON.stringify({ query, variables: { id: 'tt0111161' } })
});

if (!response.ok) {
  throw new Error(`IMDb API HTTP ${response.status}`);
}
const payload = await response.json();
if (payload.errors) throw new Error(JSON.stringify(payload.errors));
console.log(JSON.stringify(payload.data.title, null, 2));

Request only fields you use, retry transient failures with bounded exponential backoff, and cache responses when the license permits. Keep keys in environment variables or a secret manager. Confirm whether your subscription permits storage, redistribution, and commercial use.

Parse HTML only when you are authorized

Cheerio for server-delivered markup

Cheerio parses received HTML or XML with jQuery-like selectors; it does not execute JavaScript. Install it with npm install cheerio. Prefer stable attributes or embedded structured data over brittle positional selectors.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
import * as cheerio from 'cheerio';

const page = await fetch(process.env.AUTHORIZED_IMDB_URL, {
  headers: { 'user-agent': 'YourAppName/1.0 (contact@example.com)' }
});
if (!page.ok) throw new Error(`HTTP ${page.status}`);
const html = await page.text();
const $ = cheerio.load(html);

const title = $('h1').first().text().trim() || null;
const ratingText = $('[data-testid="hero-rating-bar__aggregate-rating__score"]')
  .first().text().trim();
const rating = ratingText ? Number.parseFloat(ratingText) : null;
console.log({ title, rating });

Selectors are not an IMDb data contract and can change without notice. Cheerio’s fromURL helper follows redirects (up to five), rejects non-2xx responses, and accepts request options such as a descriptive user-agent, but use it only under your authorization.

Puppeteer when JavaScript creates the fields

Use Puppeteer or Playwright when an authorized target inserts the required data after page load. Puppeteer controls Chrome or Firefox and runs headless by default.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage();
  await page.setUserAgent('YourAppName/1.0 (contact@example.com)');
  await page.goto(process.env.AUTHORIZED_IMDB_URL, {
    waitUntil: 'domcontentloaded',
    timeout: 30000
  });
  await page.waitForSelector('[data-testid="hero-rating-bar__aggregate-rating__score"]', {
    timeout: 15000
  });
  const data = await page.evaluate(() => ({
    title: document.querySelector('h1')?.textContent?.trim() ?? null,
    rating: document.querySelector('[data-testid="hero-rating-bar__aggregate-rating__score"]')?.textContent?.trim() ?? null
  }));
  console.log(data);
} finally {
  await browser.close();
}

Wait for a known selector rather than sleeping for an arbitrary number of seconds. Capture the final HTML or an authorized network response for debugging, throttle requests, and close the browser in a finally block.

Data-quality rules that prevent bad catalogs

  • Convert N to null before numeric parsing.
  • Parse averageRating as a decimal and numVotes as an integer.
  • Join ratings and basics on the exact string tconst.
  • Store retrieved_at, the dataset revision or retrieval date, the API product revision, or the authorized page URL and permission basis.
  • Validate titleType === 'movie' before movie-only reporting.
  • Do not infer a zero rating, zero votes, unknown year, or zero runtime from a missing value.
  • Expect ratings to change between daily dataset refreshes and real-time API requests.

Performance, reliability, and cost decisions

Bulk files

Bulk imports spend bandwidth and disk once per refresh, then make local queries cheap. Stream decompression, process one line at a time, and write checkpoints so an interrupted job can resume by file. Download to temporary storage, verify the HTTP status before gunzipping, and retain the retrieval timestamp. A complete multi-table import needs substantially more storage and I/O than a few title lookups.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

GraphQL

The API avoids downloading unrelated columns and is better for interactive search, but every request depends on network availability and subscription limits. Select only required fields, bound retries, cache permitted responses, and monitor authorization failures separately from timeouts.

Browser automation

A real browser consumes considerably more CPU and memory than Cheerio. Reuse a browser process carefully, limit concurrency, set navigation and selector timeouts, and record the URL, response status, and failure reason. A browser cannot make an unauthorized extraction permissible.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting

Symptom Likely cause Fix
HTTP 404 or a gunzip error Wrong dataset URL, a proxy response, or an incomplete download Check the exact datasets.imdbws.com URL, verify status before decompression, and retry the download.
All fields are null The parser treated N as a value or converted before checking it Map N to null first, then parse numbers.
Ratings are missing after the join tconst was coerced, trimmed incorrectly, or the title has no rating row Keep IDs as strings, compare exact IDs, and represent an absent rating as null.
A series appears in a movie report No title-type validation Filter or validate titleType before displaying movie-only results.
Cheerio finds no rating The value is inserted by client-side JavaScript or the selector changed Use an authorized browser path, inspect the final DOM, and replace brittle selectors.
Puppeteer times out Slow navigation, a changed selector, or an unavailable page Check the response status, wait for a documented selector, increase the timeout modestly, and log the final URL. Do not attempt to bypass access controls.
GraphQL returns authorization errors Missing AWS subscription, expired credentials, or incorrect product-specific signing Verify the AWS account and subscription, rotate credentials through a secret manager, and follow that product’s authentication instructions.

Or skip the browser setup

For screenshot APIs, ScreenshotNeo is the first option to try because it removes consent banners, popups, and chat widgets before capture, bills only clean shots, and has the lowest paid plan. It is a screenshot service, not a replacement for IMDb’s structured datasets or licensed API; use it when you need a visual capture of an authorized page.

A single request returns PNG, JPEG, WebP, or PDF. The API base is https://api.screenshotneo.com/v1/shot. See the ScreenshotNeo documentation for all options.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://www.imdb.com/title/tt0111161/ -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://www.imdb.com/title/tt0111161/"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://www.imdb.com/title/tt0111161/' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo has 63 options, including full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device and retina settings, PDFs, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Parameters used by other screenshot APIs also work.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing result. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to begin.

Recommended production architecture

  1. Use the daily TSV pipeline for permitted non-commercial bulk catalogs.
  2. Store normalized fields plus the original source row, retrieval timestamp, and dataset date.
  3. Use the licensed GraphQL API for real-time search or applications that need only a few fields.
  4. Use Cheerio only for authorized, server-delivered HTML and Puppeteer or Playwright only for authorized client-rendered pages.
  5. Keep screenshots separate from structured data; a screenshot is useful for visual evidence, not reliable rating extraction.

Frequently Asked Questions

Can I use the TSV importer in a serverless function?

Yes, for small targeted jobs if the runtime permits the download time and temporary storage. Full daily files are usually better handled by a scheduled worker with persistent storage and resumable checkpoints.

Does ScreenshotNeo return IMDb ratings as JSON?

No. ScreenshotNeo returns a rendered image or PDF. Use IMDb’s datasets or its licensed GraphQL product when you need structured ratings and metadata.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How can I test the parser without downloading the full datasets?

Create a tiny local TSV fixture with the official header and two rows, including one row containing N, then run the same row-normalization and join functions against that fixture before enabling the remote URLs.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.