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

Pass arguments after the callback: page.evaluate(function, arg1, arg2, ...). The callback runs inside the web page, so values from your PhantomJS script must be supplied explicitly and must be JSON-serializable. This interface has supported argument passing since PhantomJS 1.6.

The argument-passing syntax

page.evaluate() takes the function to run first, followed by the values that function expects. PhantomJS supplies those trailing values as the callback’s parameters, in the same order.

var heading = page.evaluate(function(selector) {
  var element = document.querySelector(selector);
  return element ? element.textContent : null;
}, 'h1');

Here, 'h1' is passed to the callback’s selector parameter. The function is evaluated in the page context, where document, window and the page’s DOM are available.

A complete runnable PhantomJS example

This script opens a page, checks the load status, passes a selector into evaluate(), prints the returned text and exits cleanly.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
var page = require('webpage').create();

page.open('https://example.com', function(status) {
  if (status !== 'success') {
    console.log('Unable to load page');
    phantom.exit();
    return;
  }

  var heading = page.evaluate(function(selector) {
    var element = document.querySelector(selector);
    return element ? element.textContent : null;
  }, 'h1');

  console.log(heading);
  phantom.exit();
});

Check status before reading content. The null check prevents a missing element from causing a property error; it is a defensive choice rather than a special guarantee of evaluate().

Passing more than one value

Append additional arguments in parameter order. Primitive values, arrays and plain objects are the safest choices because PhantomJS serializes values across the browser boundary.

var result = page.evaluate(function(selector, minimumLength, includeHidden) {
  var nodes = document.querySelectorAll(selector);
  var output = [];

  for (var i = 0; i < nodes.length; i += 1) {
    var node = nodes[i];
    if (!includeHidden && node.offsetParent === null) {
      continue;
    }
    var text = node.textContent.trim();
    if (text.length >= minimumLength) {
      output.push(text);
    }
  }

  return output;
}, 'p', 20, false);

The callback receives 'p', then 20, then false. If you change the order at the call site, the parameters change meaning too.

Use a serializable options object

For several related settings, pass one plain object. Keep its properties to strings, numbers, booleans, arrays and nested plain objects.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
var options = {
  selector: '.price',
  attribute: 'data-value',
  limit: 10
};

var values = page.evaluate(function(config) {
  var elements = document.querySelectorAll(config.selector);
  var result = [];

  for (var i = 0; i < elements.length && i < config.limit; i += 1) {
    var value = elements[i].getAttribute(config.attribute);
    if (value !== null) {
      result.push(value);
    }
  }

  return result;
}, options);

Think of the object as data, not as a live reference. PhantomJS serializes it before the page-side function receives it.

Rank #2
Sale

The page context is a hard boundary

A callback passed to evaluate() does not close over variables in the outer PhantomJS script. This common mistake leaves selector undefined inside the page:

var selector = 'h1';
var text = page.evaluate(function() {
  return document.querySelector(selector).textContent;
});

Pass the variable explicitly instead:

var selector = 'h1';
var text = page.evaluate(function(s) {
  var element = document.querySelector(s);
  return element ? element.textContent : null;
}, selector);

The same rule applies to configuration objects, counters, regular expressions and helper values. Define page-side helpers inside the callback or pass only data they need.

Values that cannot cross the boundary

PhantomJS documents closures, functions and DOM nodes as unsupported arguments. Do not pass document.querySelector('h1'), a callback function or an object containing methods. Convert a DOM node to text or an attribute inside the page context, then return that simple value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
var title = page.evaluate(function() {
  var node = document.querySelector('h1');
  return node ? {
    text: node.textContent,
    id: node.id
  } : null;
});

Return simple data to PhantomJS

The return path has the same serialization constraint. Return strings, numbers, booleans, arrays or plain objects. A DOM element, function or closure will not be useful outside the page.

var links = page.evaluate(function() {
  var anchors = document.querySelectorAll('a');
  var result = [];

  for (var i = 0; i < anchors.length; i += 1) {
    result.push({
      text: anchors[i].textContent,
      href: anchors[i].href
    });
  }

  return result;
});

Large result sets increase serialization and memory cost. Select only the fields you need, and paginate or limit the collection when a page contains thousands of nodes.

Forwarding console messages

console.log() called inside the page is not automatically printed in the PhantomJS terminal. Register page.onConsoleMessage if page-side diagnostics are required.

var page = require('webpage').create();

page.onConsoleMessage = function(message) {
  console.log('[page] ' + message);
};

page.open('https://example.com', function(status) {
  if (status !== 'success') {
    console.log('Unable to load page');
    phantom.exit();
    return;
  }

  page.evaluate(function(label) {
    console.log('Evaluating selector: ' + label);
  }, 'h1');

  phantom.exit();
});

When practical, return a diagnostic value instead of relying on console forwarding; returned data is easier for the outer script to test and log consistently.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

evaluate() versus evaluateJavaScript()

These APIs accept different forms of input. Use the regular method when you need documented trailing arguments.

API Input form Argument guidance Typical use
page.evaluate(function, arg1, arg2, ...) A JavaScript function object Pass JSON-serializable values after the function Selectors, options and extracted page data
page.evaluateJavaScript(str) A string containing a function declaration The reference documents immediate invocation, not the same trailing-argument list Evaluating function text, often with page globals set or read in separate calls

If your code needs a selector or configuration value, prefer page.evaluate() and pass it explicitly. Treat evaluateJavaScript() as a related but separate entry point rather than assuming the two signatures are interchangeable.

Useful argument-passing patterns

Selectors supplied by a caller

Keep selector input outside the callback and pass it as data. Validate or constrain selectors when they originate from users, because invalid CSS produces a page-side query error.

Flags and numeric limits

Booleans and numbers cross cleanly. Name them clearly in the callback, for example includeHidden or maxItems, and enforce limits inside the page function rather than trusting the caller.

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

Arrays of values

Pass an array when the page must match several selectors or IDs. Use a loop in the callback and return a plain array of results. Avoid putting functions or DOM nodes in the array.

Data prepared from PhantomJS modules

Read files, environment variables or command-line arguments in the outer script, convert them to plain data, then pass that data to evaluate(). The page callback cannot access PhantomJS modules or the outer script’s filesystem directly.

Troubleshooting

Symptom Likely cause Fix
ReferenceError: selector is not defined The callback tried to use an outer variable without receiving it. Add a callback parameter and append the variable after the function.
The callback receives undefined The argument was omitted, misspelled, or placed before the function. Use page.evaluate(function(value) { ... }, value) and verify spelling and order.
An object arrives empty or behaves unexpectedly It contains methods, functions, DOM nodes or unsupported values. Build a JSON-style object containing only primitives, arrays and plain nested objects.
A returned element cannot be inspected outside the page DOM nodes do not cross the boundary as usable return values. Extract text, attributes or a plain object inside the callback.
Page logs do not appear in the terminal Page-context console output is not forwarded by default. Set page.onConsoleMessage, or return the diagnostic text.
Properties are missing from the result The page was not loaded successfully, or the selector matched nothing. Check the page.open status, wait for the required content, and null-check queried elements.
Evaluation fails only on newer sites PhantomJS is legacy software and may not support modern browser APIs or scripts. Confirm the installed PhantomJS version, simplify the page-side code, or move capture work to a maintained browser.

Reliability and performance considerations

  • Perform one evaluation that gathers the required fields instead of many evaluations that repeatedly cross the browser boundary.
  • Keep callbacks deterministic: pass all inputs, avoid hidden state, and return a compact result.
  • Wait for the page’s content before evaluating. A successful network load does not guarantee that asynchronous application data has rendered.
  • Use defensive checks for missing elements and unexpected types. A callback that returns null for an absent node is easier to handle than one that throws.
  • Measure serialization size when passing large configuration objects or returning many records. Smaller payloads reduce memory use and execution time.
  • Pin and verify the PhantomJS version in old build environments. The documented argument feature begins with PhantomJS 1.6, while the project itself is legacy software.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If the actual deliverable is a visual image or PDF rather than values extracted from the DOM, ScreenshotNeo is the first alternative to try: it provides clean screenshots through one request, removes common consent banners, newsletter popups and chat widgets before capture, and bills only clean shots.

For a direct image request, see the ScreenshotNeo API documentation:

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://stripe.com -o shot.webp

The same request in Python:

import requests

r = requests.get(
    'https://api.screenshotneo.com/v1/shot',
    params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'},
    timeout=90
)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)

And in Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo is not a replacement for page.evaluate() when you need structured DOM data. It is useful when you need a rendered artifact and want to avoid maintaining a browser script. Bot checks, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify the page verdict and whether the request was billed. Its MCP server exposes take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.

Frequently Asked Questions

Can I pass an asynchronous callback as an argument?

No. Functions are unsupported across the evaluate boundary. Pass data instead, and define asynchronous page logic inside the callback if the PhantomJS version and page timing allow it.

Does PhantomJS copy or reference an argument object?

It serializes the value for the page context, so changes made inside the callback do not update the original outer object.

What should I do when a selector contains quotes?

Pass the selector as a string argument rather than concatenating it into callback source; this avoids quoting errors and keeps the callback reusable.

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

Is PhantomJS suitable for a new browser-automation project?

It is legacy software. Keep it for compatible maintenance work, but evaluate a maintained browser engine for new projects that require modern web-platform support.

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.