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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

The error is caused by JavaScript input that starts with a top-level return. JavaScript only permits return inside a function body. In the reported requests-html example, pass a complete arrow function to render(script=...), with the return statement inside its braces. The page response is not the cause established by that example.

What “Unexpected Token Return” means

return is a statement, not a standalone JavaScript expression. This is invalid when evaluated as top-level code:

return Highcharts.charts[0].series[0].data.map(d => d.y);

The browser’s JavaScript parser encounters return where it expects a valid expression or function. It raises a syntax error before the requested data can be returned. The error message therefore points to the form of the JavaScript supplied for evaluation; it does not, by itself, indicate that the web page sent a bad response.

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

The reported case used resp.html.render(script=script, reload=False), from requests-html. Its accepted answer fixes the input by passing a function expression:

script = """() => {
    return Highcharts.charts[0].series[0].data.map(d => d.y);
}"""
chartdata = resp.html.render(script=script, reload=False)

The key change is that the return now sits inside the arrow function’s body. This is the demonstrated form for that requests-html call; do not assume every wrapper accepts the same string format.

Apply the fix in requests-html

  1. Keep the call you actually use. The example concerns resp.html.render(script=..., reload=False), not every method named evaluate.
  2. Wrap the JavaScript body in a function. Pass () => { ... } as the script, and put each return inside the braces.
  3. Inspect the exact string. If it still fails, print or log the final value of script immediately before calling render. Check that the wrapper received the arrow function, not an older or separately constructed top-level return.

For the Highcharts expression in the reported example, the function returns an array of each point’s y value. That expression still depends on the page having the expected Highcharts object and chart data; the syntax correction does not establish that those page objects exist or that the page has finished loading them.

How direct Pyppeteer evaluation differs

Direct Pyppeteer Page.evaluate is a different API from requests-html’s render(script=...). The Pyppeteer 0.0.25 reference describes Page.evaluate as executing a JavaScript function or expression and returning the result; it also documents force_expr, which defaults to false and controls expression treatment. Check the method signature and behavior for the Pyppeteer version installed in your environment before changing how you pass code.

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

For a direct Pyppeteer call, use a function form when your code needs a return:

result = await page.evaluate("""() => {
    return Highcharts.charts[0].series[0].data.map(d => d.y);
}""")

This illustrates function-shaped input, but it is not proof that every old wrapper or version parses a string in precisely the same way. If this direct call fails, consult the installed version’s API behavior rather than copying rules inferred from requests-html. Current Puppeteer documentation likewise describes evaluation with a function or string and recommends a function for easier debugging, but its documentation identifies Puppeteer 25.12.0; it is a comparison, not a guarantee about a Python wrapper.

Call site What the cited material establishes What to verify
requests-html render(script=...) The reported working input is a complete arrow function with return inside its body. That the exact installed wrapper receives the function string and that the page exposes the objects your expression uses.
Pyppeteer 0.0.25 Page.evaluate The reference says it executes a function or expression and documents force_expr. The installed Pyppeteer and Chromium versions, and how that version interprets your specific argument.
Current Puppeteer documentation, version 25.12.0 It describes evaluation from a function or string and says function form is easier to debug. Do not treat this JavaScript Puppeteer reference as the contract for an older Python wrapper.

Debug the remaining evaluation failure

  • Confirm which method is called. Write down whether the failing line is requests-html .html.render(script=...), direct Pyppeteer page.evaluate(...), or another wrapper. Similar method names do not prove identical input handling.
  • Reduce the script. First test the smallest function or expression accepted by that specific API, then add the page-specific lookup. This separates an input-form problem from a problem in the expression itself.
  • Check page assumptions separately. Once the syntax is accepted, an absent Highcharts object, an unavailable chart at index 0, or data that is not ready can cause a different failure. Those are not established causes of the reported syntax error, but they are dependencies of the sample expression.
  • Record the environment. Note Python package versions and the Chromium version alongside the full traceback. Pyppeteer’s documentation says it works best with its bundled Chromium and does not guarantee compatibility with other Chromium versions.

Common symptoms, causes, and fixes

Symptom Likely distinction to check Next step
SyntaxError: Unexpected token return on the reported render call The script starts with a top-level return. Pass the full arrow function shown above to the reported requests-html call.
The same syntax error after editing The actual string passed may still differ from the edited source, or the caller may be a different wrapper. Log the exact string and identify the method receiving it.
Syntax error with direct page.evaluate Direct Pyppeteer has its own function/expression behavior and options. Check the installed version’s Page.evaluate documentation, including force_expr where applicable.
A different error after the syntax fix The JavaScript may now parse but rely on a page object, chart, or data that is unavailable. Inspect the new traceback and validate each page-side object independently.
Failures vary by machine or browser installation Pyppeteer/Chromium compatibility may be involved in browser issues beyond this syntax error. Capture exact package and Chromium versions; Pyppeteer documents its bundled Chromium as the best-supported pairing.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When the task is a screenshot instead of data extraction

The fix above is for executing JavaScript and returning a value. If your actual goal is a rendered website image or PDF rather than reading chart data in Python, ScreenshotNeo is a separate screenshot API and MCP server; it is not a drop-in replacement for the JavaScript evaluation in this example.

Or skip the browser setup

Use one GET request to request a screenshot. See the ScreenshotNeo API documentation for its 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://stripe.com -o shot.webp

Python:

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

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}`);
  • Cookie and consent banners are accepted before capture, and more than 60 known consent platforms, newsletter popups, and chat widgets are removed; each step can be turned off.
  • Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers identify the page verdict and billing status.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents 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. All features are on every plan.

Sign up for ScreenshotNeo to get 1,000 screenshots a month free, with no card.

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.