Hey there, fellow developer!
Remember PhantomJS? That trusty headless browser that helped us scrape websites, run automated tests, and generate screenshots back in the day? Well, if you’re still using it or just discovered some legacy code that relies on it, I’ve got some news for you.
PhantomJS officially threw in the towel back in 2018. The maintainers basically said „thanks for all the fish“ and moved on to bigger and better things. But don’t worry – the ecosystem didn’t just leave us hanging. There are some fantastic alternatives that are not only actively maintained but actually blow PhantomJS out of the water in terms of features, performance, and reliability.
In this guide, I’ll walk you through the best PhantomJS alternatives available today, complete with real-world examples you can copy and paste into your projects. Whether you’re migrating legacy code or starting fresh, I’ve got you covered.
Why You Need PhantomJS Alternatives
PhantomJS was a popular headless browser based on WebKit that was discontinued in 2018. The main reasons to migrate to modern alternatives include:
- No longer maintained – Security vulnerabilities and bugs won’t be fixed
- Outdated web standards – Missing modern JavaScript features and APIs
- Performance issues – Slower than modern alternatives
- Limited browser support – Only WebKit-based rendering
Top PhantomJS Alternatives
1. Puppeteer (Recommended)
Best for: Chrome/Chromium automation, Node.js projects
Puppeteer is a Node.js library that provides a high-level API to control Chrome or Chromium over the DevTools Protocol. It’s maintained by the Google Chrome DevTools team.
We see Puppeteer actively used for AI / MCP Servers. A MCP server is a component of the Model Context Protocol (MCP), an open standard that allows AI models, especially large language models (LLMs), to access and interact with external data, tools, and services.
Key Features:
- Headless and full (headed) Chrome support
- Built-in screenshot and PDF generation
- Performance monitoring
- Network interception
- JavaScript execution
Installation:
|
1 2 3 4 5 |
npm install puppeteer # or for library-only (no Chrome download) npm install puppeteer-core |
Basic Example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import puppeteer from 'puppeteer'; (async () => { // Launch browser const browser = await puppeteer.launch(); const page = await browser.newPage(); // Navigate to page await page.goto('https://example.com'); // Take screenshot await page.screenshot({path: 'example.png'}); // Get page content const content = await page.content(); console.log(content); // Close browser await browser.close(); })(); |
Advanced Example – Web Scraping:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import puppeteer from 'puppeteer'; (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://news.ycombinator.com'); // Extract data const articles = await page.evaluate(() => { const items = document.querySelectorAll('.athing'); return Array.from(items).map(item => { const title = item.querySelector('.storylink')?.textContent; const link = item.querySelector('.storylink')?.href; return { title, link }; }); }); console.log(articles); await browser.close(); })(); |
Links:
2. Playwright (Cross-browser champion)
Best for: Cross-browser testing, modern web apps
Playwright is a framework developed by Microsoft that enables reliable end-to-end testing for modern web applications across multiple browsers.
Key Features:
- Cross-browser support (Chromium, Firefox, WebKit)
- Auto-wait capabilities
- Multiple language support (JavaScript, Python, Java, .NET)
- Mobile emulation
- Network interception and mocking
Installation:
|
1 2 3 4 5 |
npm init playwright@latest # or just the library npm install playwright |
Basic Example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { chromium } from 'playwright'; (async () => { const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); // Auto-wait for elements await page.click('button:text("Click me")'); // Screenshot await page.screenshot({ path: 'example.png' }); await browser.close(); })(); |
Cross-browser Testing Example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { chromium, firefox, webkit } from 'playwright'; const browsers = [chromium, firefox, webkit]; for (const browserType of browsers) { const browser = await browserType.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); // Test functionality across browsers const title = await page.title(); console.log(`${browserType.name()}: ${title}`); await browser.close(); } |
Links:
3. Selenium WebDriver (Mature ecosystem)
Best for: Cross-browser testing, legacy system integration
Selenium WebDriver is a mature automation framework that supports multiple browsers and programming languages.
Key Features:
- Extensive browser support (Chrome, Firefox, Safari, Edge, IE)
- Multiple language bindings
- Large ecosystem and community
- Grid support for parallel testing
- Mobile testing capabilities
Installation (Python):
|
1 2 3 |
pip install selenium |
Installation (Node.js):
|
1 2 3 |
npm install selenium-webdriver |
Example (Python):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from selenium import webdriver from selenium.webdriver.chrome.options import Options # Configure Chrome options chrome_options = Options() chrome_options.add_argument('--headless') # Launch browser driver = webdriver.Chrome(options=chrome_options) try: driver.get('https://example.com') # Find element and interact element = driver.find_element('tag name', 'h1') print(element.text) # Take screenshot driver.save_screenshot('example.png') finally: driver.quit() |
Example (Node.js):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import { Builder, By, until } from 'selenium-webdriver'; import chrome from 'selenium-webdriver/chrome.js'; const options = new chrome.Options(); options.addArguments('--headless'); const driver = new Builder() .forBrowser('chrome') .setChromeOptions(options) .build(); try { await driver.get('https://example.com'); const element = await driver.findElement(By.tagName('h1')); const text = await element.getText(); console.log(text); await driver.takeScreenshot().then(data => { require('fs').writeFileSync('example.png', data, 'base64'); }); } finally { await driver.quit(); } |
Links:
4. Chrome Headless + DevTools Protocol (Direct approach)
Best for: Low-level control, performance-critical applications
Direct usage of Chrome’s headless mode with the DevTools Protocol for maximum control.
Basic Command Line Usage:
|
1 2 3 4 5 6 7 8 9 10 |
# Launch headless Chrome google-chrome --headless --remote-debugging-port=9222 --disable-gpu # Take screenshot google-chrome --headless --disable-gpu --screenshot=example.png https://example.com # Generate PDF google-chrome --headless --disable-gpu --print-to-pdf=example.pdf https://example.com |
Example with DevTools Protocol (Node.js):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import CDP from 'chrome-remote-interface'; (async () => { const client = await CDP(); const { Network, Page, Runtime } = client; await Network.enable(); await Page.enable(); await Page.navigate({ url: 'https://example.com' }); // Wait for page load await Page.loadEventFired(); // Take screenshot const screenshot = await Page.captureScreenshot(); require('fs').writeFileSync('example.png', screenshot.data, 'base64'); await client.close(); })(); |
Links:
Alternative Tools Summary
Other Notable Options:
Nightmare.js
- Node.js library built on Electron
- Simpler API than Puppeteer
- No longer actively maintained
|
1 2 3 4 5 6 7 8 9 |
import Nightmare from 'nightmare'; const nightmare = Nightmare({ show: false }); const result = await nightmare .goto('https://example.com') .evaluate(() => document.title) .end(); |
CasperJS
- Built on top of PhantomJS (legacy)
- Deprecated along with PhantomJS
Zombie.js
- Lightweight, Node.js-based
- Fast but limited JavaScript support
- Good for simple page interactions
|
1 2 3 4 5 6 7 |
import Browser from 'zombie'; const browser = new Browser(); await browser.visit('https://example.com'); console.log(browser.text('title')); |
Recommendation Guide
Choose Puppeteer if:
- You’re working with Node.js/JavaScript
- You only need Chrome/Chromium support
- You want the most stable and well-maintained solution
- You need advanced Chrome features (DevTools, performance monitoring)
Choose Playwright if:
- You need cross-browser testing
- You want modern testing features (auto-wait, tracing)
- You’re building a comprehensive testing suite
- You work with multiple programming languages
Choose Selenium if:
- You have existing Selenium infrastructure
- You need support for older browsers
- You’re working with multiple programming languages
- You need the largest ecosystem and community support
Choose Chrome Headless directly if:
- You need maximum performance
- You want minimal dependencies
- You’re building low-level automation tools
- You need direct DevTools Protocol access
Feature Comparison
Feature | Puppeteer | Playwright | Selenium | Chrome Headless |
|---|---|---|---|---|
Browsers | Chrome/Chromium | Chrome, Firefox, Safari | All major browsers | Chrome only |
Languages | JavaScript/TypeScript | JS, Python, Java, .NET | Multiple | Any (via Protocol) |
Performance | Excellent | Excellent | Good | Excellent |
Ease of Use | Good | Excellent | Fair | Basic |
Community | Large | Growing | Very Large | Medium |
Maintenance | Active | Active | Active | Active |
Migration Tips from PhantomJS
Common PhantomJS patterns and their modern equivalents:
Taking Screenshots:
|
1 2 3 4 5 6 7 8 9 10 |
// PhantomJS page.render('screenshot.png'); // Puppeteer await page.screenshot({path: 'screenshot.png'}); // Playwright await page.screenshot({path: 'screenshot.png'}); |
Page Evaluation:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
// PhantomJS var title = page.evaluate(function() { return document.title; }); // Puppeteer const title = await page.evaluate(() => document.title); // Playwright const title = await page.evaluate(() => document.title); |
Waiting for Elements:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
// PhantomJS (manual waiting) setTimeout(function() { // check if element exists }, 1000); // Puppeteer await page.waitForSelector('.my-element'); // Playwright (auto-wait) await page.click('.my-element'); // automatically waits |
