GPTBot downloads your JavaScript. It does not run it.
Table of contents
When a crawler requests your JavaScript files, it is tempting to read that as “it renders the page”. Our logs say otherwise. OpenAI’s GPTBot downloaded the JavaScript bundle of our test bed page by page, and the React code in it never ran. Googlebot, Applebot and one of Meta’s crawlers did the same in this window: they fetched the files, and our execution beacon stayed silent.
Which OpenAI agent does what
OpenAI runs several agents with separate user agents and separate published IP lists. Splitting by both shows that only one of them touches JavaScript or CSS.
| Agent | What it is for | IP list it came from | Requests | Pages | robots.txt | JS | CSS | Other files |
|---|---|---|---|---|---|---|---|---|
| GPTBot/1.4 | training data | gptbot.json | 141 | 56 | 0 | 36 | 0 | 45 sitemaps and feeds |
| OAI-SearchBot/1.4 | ChatGPT search index | searchbot.json | 577 | 560 | 0 | 0 | 0 | 2 images, 1 font, 1 llms.txt, 1 feed |
OAI-SearchBot/1.4 with a robots.txt; token |
reads the rules for OpenAI | gptbot.json and searchbot.json | 92 | 0 | 92 | 0 | 0 | none |
| OAI-SearchBot/1.0 | reads the rules | searchbot.json | 66 | 0 | 66 | 0 | 0 | none |
| ChatGPT-User/1.0 | fetches a page when a user asks ChatGPT | chatgpt-user.json | 362 | 361 | 0 | 0 | 0 | 1 JSON data file |
Both sites, jsseo.dev and the test bed next.jsseo.dev, 23 October to 14 November 2026. Only requests from addresses on the matching OpenAI list are counted. GPTBot’s remaining 4 requests were our beacon; OAI-SearchBot’s remaining 12 were /favicon.ico, which does not exist.
- The JavaScript came from GPTBot, the training crawler. Its user agent was the plain
GPTBot/1.4, and all 10 addresses are on OpenAI’s GPTBot list, none on the search or ChatGPT-User lists. It is not ChatGPT fetching a page for a user. - ChatGPT-User fetched pages and almost nothing else. No JavaScript, no CSS, no images; the one exception is a JSON data file that our data page links to.
- OAI-SearchBot fetched pages, not scripts or styles. Every page on jsseo.dev links one stylesheet and preloads one font. In 560 page fetches OAI-SearchBot requested the stylesheet zero times and the font once.
- The robots.txt readers fetched nothing but robots.txt. The tagged variant that reads the rules for GPTBot, described in our earlier finding, made 92 requests, all of them for
/robots.txt. A second, untagged reader,OAI-SearchBot/1.0, did the same 66 times.
Requests that claim an OpenAI user agent from addresses on no OpenAI list are left out. There were 184 of them, among them 4 for .js files that do not exist, all answered with a 404 or a redirect.
How GPTBot fetched the bundle
On 30 October at 03:03 UTC, GPTBot crawled the test bed from one address in 44 seconds. Between 1 and 15 seconds after each page, usually about 6, it requested that page’s own JavaScript chunk, the file named in a <script src> tag of the HTML. At the start it fetched the six chunks shared by every page. That is 30 JavaScript files in one session.
Then the page code had a chance to run. It did not:
- The React beacon never fired. Our test bed reports JavaScript execution through a React component, which runs only once the bundle has been evaluated and the page hydrated. GPTBot downloaded that bundle and never sent the component’s beacon.
- The inline beacon did. A small script written directly into the HTML fired on one page, two minutes after the crawl, then three more times at 30-minute intervals from the same address. That is the inline-only pattern we described in August: GPTBot runs a plain inline script, not the React app.
On 9 November it fetched the home page and 13 test pages, and the six shared chunks again, but no page chunks. No beacon fired at all.
Downloading is not running
The same holds beyond OpenAI. For each crawler on the test bed we compared three things: page fetches, JavaScript files fetched, and beacons from the React component.
| Crawler (verified) | Test bed pages | JS files fetched | React beacon | Inline beacon |
|---|---|---|---|---|
| GPTBot | 52 | 36 | 0 | 4 |
| Googlebot | 0 | 38 | 0 | 0 |
| Applebot | 6 | 20 | 0 | 0 |
| meta-webindexer | 110 | 10 | 0 | 0 |
| Meta-ExternalAgent | 16 | 26 | 16 | 16 |
| Amazonbot | 51 | 0 | 0 | 0 |
| CCBot | 23 | 0 | 0 | 0 |
23 October to 13 November 2026 for pages and beacons (the tracker snapshot), to 14 November for JavaScript files. Pages are test cells only, verified requests only.
Four groups appear:
- Downloads and runs: Meta-ExternalAgent. It fetched the chunks and fired both beacons in the same visit on 12 November.
- Downloads, nothing ran in this window: GPTBot, Googlebot, Applebot and meta-webindexer. Googlebot and Applebot did run our React code earlier (Googlebot 11 times between May and 4 October, Applebot 48 times in July and August), so for them this is a quiet window, not a fixed trait. Googlebot fetched its 38 files without fetching a single test page, which fits Google’s documented practice of fetching and caching page resources separately from pages.
- Does not download: Amazonbot and CCBot crawled the test pages and fetched no JavaScript. ClaudeBot made no test-page request in this window, and on jsseo.dev it fetched no
.jsor.cssfile either. - Unverifiable: ElevenlabsCrawler fetched 25 chunks from 25 addresses at hosting providers on 25 October, and 5 React beacons arrived under its user agent. ReflectionBot fetched 7 and sent 5. Neither publishes a way to verify its addresses.
On jsseo.dev, which serves one stylesheet and one small Cloudflare script, CSS came from Googlebot (8 requests), Applebot (18), Google’s inspection and safety tools, and once from Bingbot. No verified AI crawler requested it in this window.
What about OAI-SearchBot?
In November 2026 several SEO practitioners reported that OAI-SearchBot has started fetching JavaScript, CSS and API endpoints, and that ChatGPT’s index copy of some JavaScript pages looks rendered. One developer reported Next.js ?_rsc= requests, which normally appear only when JavaScript runs in a browser, from OAI-SearchBot and GPTBot since late September. Our data does not show that, with one important limit.
- No scripts, no styles, no API calls. On jsseo.dev, OAI-SearchBot fetched 560 pages in three weeks and no
.jsor.cssfile. It requested nothing under/api/. - No runtime URLs. No request from a verified OpenAI agent carried an
_rscparameter. The only query strings were GPTBot’s beacon and pagination links (?page=2,?page=3) that sit as plain<a href>in our HTML, so fetching them needs no JavaScript. - The limit: OAI-SearchBot has never crawled our test pages. Since May it has read the test bed’s robots.txt 431 times and requested no test cell; the 12 cell requests under its name all failed verification. Our JavaScript test pages cannot say whether OAI-SearchBot renders. They only say it has not come to look.
So on our sites, the agent that fetched OpenAI’s JavaScript was GPTBot, and GPTBot did not run React. If OAI-SearchBot renders, it does so on sites it crawls more deeply than ours.
A file is a URL: the llms.txt parallel
A request for a JavaScript file is a crawler following a URL in the HTML. The same mechanism explains the one change we have seen on llms.txt.
jsseo.dev has served an llms.txt since May 2026. Until 13 November, no page on the site linked to it, and it was in neither the sitemap nor robots.txt. In the 30 days to 26 October, not one verified AI crawler asked for it, and no OpenAI agent did in this window until 14 November.
On 13 November we published that finding, which links to /llms.txt. OAI-SearchBot fetched the post at 18:21 UTC. At 14:19 UTC the next day, OAI-SearchBot fetched /llms.txt, from an address on OpenAI’s search list. It is the first verified request for the file from any OpenAI agent in our data.
That is one request, so it shows a sequence, not a rule. But it fits the simplest explanation: crawlers do not treat llms.txt as special. Unlinked, it was ignored for six months. Linked, it was fetched like any other URL on the page. A fetch is also not use: we cannot see whether OpenAI does anything with the file, just as GPTBot’s download of our bundle did not mean it ran the code.
What this means for site owners
- Do not read
.jsrequests in your logs as rendering. GPTBot requests JavaScript and does not run React. If your content appears only after hydration, a log full of GPTBot chunk requests does not mean OpenAI’s training crawler saw it. - Split OpenAI by agent and by IP list. GPTBot (training), OAI-SearchBot (search), the robots.txt readers and ChatGPT-User behave differently. Only GPTBot fetched scripts. Each publishes its own IP list; use it.
- To know whether a crawler ran your code, measure execution, not downloads. A beacon fired from inside the code you care about is the direct test. Asset requests only show which files a crawler collected.
- A file nobody links to is a file crawlers do not fetch. That held for llms.txt for six months. If you want it fetched, link it; whether anyone uses it is a separate question.
What this does not prove
- Three weeks of asset data. Cloudflare keeps about 30 days, and before 23 October its data for our zone was incomplete; the tracker drops asset requests by design. GPTBot crawled the test bed on 19 October too, and we cannot see whether it fetched JavaScript then.
- Two GPTBot sessions with JavaScript. The pattern was the same in both, but two sessions are two sessions.
- A silent beacon is not proof that nothing ran. A renderer could evaluate the bundle and fail before the component’s effect, or block its network request. What the data shows is that our React code did not complete its first effect for GPTBot, while it did for Meta-ExternalAgent and, earlier, for Googlebot and Applebot.
- The llms.txt fetch is a single request. We cannot rule out that someone linked the file from elsewhere at the same time.
- One small site. Larger sites with more crawl budget may see different resource fetching.
Method notes
- Asset requests: every request ending in
.js,.mjsor.csson the jsseo.dev zone (jsseo.dev and next.jsseo.dev), from Cloudflare’s GraphQL analytics (httpRequestsAdaptive), 23 October to 14 November 2026. Day by day, the OpenAI requests on the test bed in this data match the tracker’s own Cloudflare-fed rows from 23 October on; before that date Cloudflare returned fewer rows than the tracker had recorded, so those days are left out. - OpenAI requests: every request whose user agent contains GPTBot, OAI-SearchBot, ChatGPT-User or OpenAI, same source and window, with the query string and the response content type. Files are counted by content type, so a 404 page for a missing favicon counts as neither a page nor an image. Each request’s address is checked against OpenAI’s four published lists (gptbot, searchbot, chatgpt-user, adsbot).
- Other verification: the tracker’s own checks: published IP lists, forward-confirmed reverse DNS for Google, Apple and Bing, AS32934 for Meta’s classes.
- Execution: the test bed fires two beacons on every page, an inline
<script>and a React client component that sends a request from its first effect. Counts from the tracker snapshot through 13 November 2026 10:24 UTC. - Pages: test cell requests from the tracker’s Cloudflare-fed rows, verified requests only.
- Analysis:
scripts/analysis/cf_assets_pull.py(with--ua-likefor the OpenAI pull) andscripts/analysis/assets_by_bot.mjs.
Data availability: methodology, tracker code and classifier are in the repository at github.com/Qbeczek1/jsseo-dev, private for now; access on request at [email protected].
Bias disclosure: I run JS SEO Lab as an independent technical SEO research project, and do paid technical SEO and AI-visibility audits through FratreSEO. No crawler vendor, search engine, or AI company funds this work.