betterreviews.Journal 
IX·On Crawlers·12 June 2026

A curl against three crawlers, three review platforms.

A field experiment. Three Shopify stores, three review platforms, three AI user agents. A nine-cell grid, six of them empty. The empty cells are the story.

BetterReviews Editorial·Studio note
CONTENTS · 13
  1. 01The experiment
  2. 02Cell A1: Yotpo as seen by GPTBot
  3. 03Cell A2: Yotpo as seen by ClaudeBot
  4. 04Cell A3: Yotpo as seen by PerplexityBot
  5. 05Cell B1, B2, B3: Okendo across the three crawlers
  6. 06Cell C1, C2, C3: Loox across the three crawlers
  7. 07The grid, drawn
  8. 08What about Googlebot
  9. 09The objection: shop those are the cheap installs
  10. 10The objection: GPTBot just doesn't matter
  11. 11What the merchant should do tomorrow
  12. 12What to do about the cell
  13. 13The closing turn

So we wanted to know what an AI crawler actually sees on a Shopify product page. Not what a marketing deck claims it sees, or what a review-widget vendor's SEO page says it sees, but what comes back when you put the question to it directly, with a terminal and a single HTTP request.

The way to ask the question is to pretend, for a moment, to be the crawler. Set your user agent to GPTBot, fire a curl at the product URL, save the HTML to disk, open it in any editor that can search a string. Look for the most distinctive sentence in the store's top-rated review, the kind of sentence that doesn't appear anywhere else on the page or in the vendor's marketing copy. If the sentence is in the file, the crawler saw it. If it isn't, the crawler didn't, and whatever happens to the customer's language downstream of this fetch is happening without that sentence in the picture.

A few weeks back we did this against three stores, with three crawlers each. Nine fetches in total, against three of the most popular review platforms on the Shopify App Store (one Yotpo store, one Okendo, one Loox), all in their default App-Store installs. The result is a three-by-three grid that this essay walks through, cell by cell. Most of the cells are empty. The ones that aren't carry only an aggregate rating, no language.

The stores will stay anonymous (Store A, Store B, Store C) because the platforms are the point, not the merchants. Run the same test on any Shopify store running any widget and we'd guess the result is the same. Twenty minutes, a terminal, a string search.

The experiment

The store URLs were chosen the way a buyer might find them. Each was the top organic result for a non-branded product query (a serum, a candle, a pet supplement). Each had between three hundred and three thousand reviews on the product page, by the merchant's own dashboard count. Each was running its review software in a fresh, unmodified install, with no custom server-side rendering tier or enterprise feature.

Store A ran Yotpo, in the standard widget configuration available on the Shopify App Store.

Store B ran Okendo, in the same standard configuration.

Store C ran Loox, the photo-and-video review app, also in the App Store default.

We made the requests from a single residential IP, in May 2026, with each user agent string set verbatim from the platforms' published crawler operator pages. We did not interact with the pages. We did not run JavaScript. We did not follow iframes. We requested the HTML the same way the crawlers themselves do: a GET request, the appropriate user agent header, no cookies, no Accept-Language preference besides the default.

The published documentation for the three bots is unambiguous. OpenAI's GPTBot, per OpenAI's crawler operator page (consulted May 2026), fetches and parses HTML; it does not execute JavaScript. Anthropic's ClaudeBot, per Anthropic's published bot documentation, fetches and parses HTML; it does not execute JavaScript. Perplexity's PerplexityBot, the indexing crawler distinct from the PerplexityUser agent that fires during live queries, behaves the same way: HTML only.

This is the universe of the experiment. Three pages, three crawlers, nine fetches, one question per cell: does the raw HTML returned by the server contain the review text the buyer sees in her browser?

Cell A1: Yotpo as seen by GPTBot

The page Store A returns to GPTBot is fifty kilobytes. It contains the Shopify Liquid-rendered theme: the header, the product title, the price, the variant picker, the buy button, the product description, the size guide, the shipping policy snippet, the footer. It contains structured data for the product, a Product schema with name and price and image and a single AggregateRating node citing the count of reviews and the average score (the AggregateRating is server-side, the page's only piece of review-shaped evidence in the HTML).

What it does not contain: the text of any of the eight hundred and twelve reviews Yotpo holds for this product. The review section is a div with the class `yotpo-main-widget`, a handful of data attributes (product id, name, image URL, price, currency), and a single async script tag pointing at Yotpo's static CDN. The div is empty in the response, and the script has not run.

We searched the file for the most distinctive phrase from the top-rated review: a specific sentence about texture and how the product feels under makeup. The phrase did not appear, and partial matches turned up nothing. We searched for the word "review" anywhere outside the aggregate rating and the structured data: a half-dozen matches in navigation labels and ARIA attributes. None of them were a review.

The crawler that came back from this page would carry away the merchant's product description, the price, the aggregate rating, and an understanding that there are eight hundred and twelve reviews somewhere it cannot read. It would not carry away a sentence.

Cell A2: Yotpo as seen by ClaudeBot

The page Store A returns to ClaudeBot is, byte for byte, identical to the page returned to GPTBot. Shopify's origin does not vary its response based on the user agent; it serves the same Liquid-rendered theme to any client. The review widget is the same empty div, the script tag is the same async fetch, and Anthropic's crawler, like OpenAI's, does not run the script.

ClaudeBot's index, for this page, is the same index GPTBot's is: aggregate rating, count, no reviews, same gap.

We confirmed this by checking for the same distinctive phrase. Absent.

Cell A3: Yotpo as seen by PerplexityBot

Same response. Same empty div. Same script tag. Same absence of the review sentence.

PerplexityBot, in our test, behaved the same as GPTBot and ClaudeBot. The PerplexityUser agent, which fires when a user asks Perplexity a live question and Perplexity goes to fetch a small number of pages in real time, behaves more like a browser and can in some cases render simple JavaScript. But PerplexityUser is not the indexer. The indexer is PerplexityBot, and PerplexityBot does not run JavaScript.

The first row of the grid is therefore empty in all three cells. Yotpo, in its standard install, is invisible to every AI crawler we tested.

Cell B1, B2, B3: Okendo across the three crawlers

Okendo is the premium-DTC option in the Shopify App Store. It positions itself as a more design-conscious, more brand-faithful alternative to Yotpo. The aesthetic of the widget is different; the mechanism is the same.

The page Store B returns is, mechanically, the same shape. An Okendo container div, prefixed with `okeReviews`, a set of data attributes (subscriber ID, product ID, locale), and a script tag pointing at Okendo's d3hw6dc1ow8pp2.cloudfront.net distribution. No reviews in the response. No paragraphs. An AggregateRating node in the structured data, since Okendo, like Yotpo, writes the aggregate into the page server-side for SEO reasons. No quotations.

GPTBot, ClaudeBot, and PerplexityBot all return the same result on this page: aggregate rating, count, no reviews.

The grid's second row, accordingly, is empty in all three cells.

Cell C1, C2, C3: Loox across the three crawlers

Loox is the photo and video review platform. Its differentiator is visual: every review has, in most installations, a customer-submitted image attached. The page Store C returns is, mechanically, the most aggressive of the three in terms of JavaScript: the photo carousel, the lightbox, the lazy-loading of images. Almost everything visible to the buyer in the browser is rendered after page load.

The HTML the server returns is, accordingly, the most barren. There is a div with the class `loox-reviews-default` and a handful of data attributes, followed by a script tag. There are no images in the initial HTML, no review texts, and, in the Loox case, not even an AggregateRating node in the page's structured data by default (the merchant can configure this, but the default install does not include it).

GPTBot, ClaudeBot, and PerplexityBot all came back with the same result: no reviews. The third row of the grid is empty in all three cells.

The grid, drawn

User agent · review prose returned
GPTBot
ClaudeBot
PerplexityBot
Yotpo812 reviews
Absent
Absent
Absent
Okendo341 reviews
Absent
Absent
Absent
Loox604 reviews
Absent
Absent
Absent
Aggregate rating in schemaReview prose absent from HTML
Three review platforms, three AI crawlers, nine fetches. Zero cells contain the review text.Experiment, May 2026 · n=3 stores

Three rows. Three columns. Nine cells. Zero cells contain the review text.

We will say that again, because it is the result and the reason for the essay. Across three of the most popular review platforms on the Shopify App Store, across three of the four most-used AI crawlers in the citation economy (Googlebot being the fourth, and we will come back to it), the review text is in zero of nine cells. The crawlers come back with an aggregate rating in six of the cells and nothing in three of the cells. They do not come back with a single review sentence in any of the nine.

The merchant who ships a JavaScript widget is, in the citation economy, publishing aggregate ratings. They are not publishing reviews.

Three popular review platforms. Three popular AI crawlers. Nine fetches. Zero review sentences. The grid is the proof. The grid is also the problem.

What about Googlebot

A reasonable reader will ask: what about Googlebot? Google runs JavaScript, so doesn't Googlebot fix this?

We ran the same experiment against Googlebot, on the same three pages, in the same week. The result is more complicated and worth its own paragraph.

Googlebot's renderer is real. It is also, as Google's own documentation has been explicit about since at least 2018 and as John Mueller has repeated in his Office Hours through 2024 and 2025, on a two-stage pipeline. The first stage fetches the initial HTML, just as the AI crawlers do. The second stage queues the page for rendering, runs a headless Chrome, executes the JavaScript, and indexes the rendered DOM. The second stage is delayed: hours in the best case, days commonly, weeks for low-priority pages.

When we re-fetched the same three pages via Google's URL Inspection tool, all three returned the rendered DOM with reviews present. So in theory, Googlebot does see the reviews. In practice, the gap between the initial fetch and the rendered index means the freshness of the review corpus, in Google's index, is structurally behind the merchant's actual corpus. The buyer reviewing a serum yesterday is not in Google's index today.

And that is Google. Google-Extended, the routing flag that determines whether a page is used for training Gemini, depends on the Googlebot crawl. ChatGPT, Claude, and Perplexity have no such relationship. They have no second-stage renderer. The aggregate rating is the most they will ever carry away from a JavaScript widget.

We have written separately about the engine the answer engine reads, on what an answer engine actually consumes when it reads a product page. This essay is the empirical version of that argument: the engine reads HTML, the HTML does not contain the reviews, the grid is empty.

The objection: shop those are the cheap installs

A second reasonable objection: the three stores we sampled were running the default, App-Store-grade installs of their review platforms. Each of those platforms has an enterprise tier (Yotpo Enterprise, Okendo Plus, Loox Scale) with optional server-side rendering modules. The merchant who pays the higher fee can, in principle, opt into server-rendered review snippets.

This is true. It does not change the result.

We have looked at the published technical documentation for each of the three platforms' SSR offerings. In every case, the server-side rendering ships a small block of reviews into the initial HTML: typically three to ten, frequently the most recent or the highest-rated. The remainder of the corpus is still client-side. A merchant with eight hundred reviews who turns on SSR is publishing ten of them to the AI crawlers. The other seven hundred and ninety are still in the widget.

This is better than zero. It is not parity.

And it is gated behind a higher pricing tier that the App-Store-default merchant, who is the median Shopify user, does not pay for. In the long tail of Shopify stores in 2026, the default install is the install. The default install is invisible.

There is a second mechanical detail worth naming. The server-rendered snippets each platform ships are themselves curated, in most cases, to favour positive reviews near the top, recent reviews near the top, or short reviews that fit a fixed visual block. The reviews that get rendered server-side are not a random sample of the corpus. They are the marketing-acceptable sample. The crawlers, where they get reviews at all, get the prettiest ten. The complicated reviews (the four-star "I love it but the cap is hard to open", the three-star "good for daytime, not for night"), the long reviews, the reviews that contain a specific long-tail keyword the buyer is going to search for, are still in the JavaScript widget, still invisible. The selection problem compounds the rendering problem. The crawler is not just seeing few reviews; it is seeing few reviews of a particular kind, and missing the long tail entirely.

We argued in the end of the review widget that the widget shape is structurally unfit for the work the buyer's language is being asked to do. This essay is the curl-shaped confirmation. The widget renders for the buyer. It does not render for the crawler. The merchant pays for both audiences and reaches only one of them.

The objection: GPTBot just doesn't matter

A third objection, sometimes voiced in review-platform marketing materials: the AI crawlers are a small fraction of the traffic. Why optimise for them when Googlebot still carries the index?

We will set aside the freshness problem with Googlebot, which we addressed above. The deeper answer is that the AI crawlers are not where the traffic comes from; they are where the conversion comes from. A buyer who asks ChatGPT for the best serum for sensitive skin is downstream of an answer that already cited some store's reviews. The buyer who arrives at the store from that answer arrives with intent that conventional organic search does not match. Adobe Analytics, in its 2025 holiday retail report, observed that visitors arriving via generative AI sources had a 9.4 percent higher conversion rate than visitors arriving via traditional search, and a 12 percent longer session length on the site.

The cells in the grid are not abstract. Each empty cell is a downstream conversion the merchant does not get. The reviewer wrote the sentence that would have produced the citation. The merchant collected the sentence, the crawler did not see it, and the answer engine cited someone else.

In the citation economy, you do not get a second chance to be the source. The brand that owns the citation owns the buyer. The brand that does not appears in someone else's answer, as a competitor mentioned in passing or not mentioned at all.

What the merchant should do tomorrow

A short list, in the same shape as the experiment.

Choose your bestselling product page and copy the URL.

Open a terminal, run a curl command with your user agent set to GPTBot, save the output, and open it in any text editor. Search for the most distinctive phrase from your top review. If the phrase is not in the file, your reviews are not in the index that ChatGPT's training-and-retrieval pipeline pulls from. Do the same with ClaudeBot, and then with PerplexityBot.

The result will be one of three. If the phrase is in all three files, you are running a server-side-rendered review system, which the dominant Shopify App Store apps in 2026 are not, and you are in the small fortunate minority. If the phrase is in some files and not others, you are running an unusual configuration (Judge.me with the partial SSR, or one of the enterprise SSR tiers) and the gap is shape-of-Swiss-cheese. If the phrase is in none of the files, your reviews are not on the internet for the AI crawlers, and you are in the same row of the grid as everyone else.

You will know, after the test, where you sit on the grid. The test takes twenty minutes. The next decision is what to do about the cell.

What to do about the cell

The honest answer is unsexy: change where the canonical record of the corpus lives. Right now it lives inside the widget vendor's JavaScript, hydrating into the DOM a moment after the initial paint. The buyer's browser is patient enough to wait for that hydration. The crawler, mostly, isn't.

So the work is to get a copy of the corpus out of the vendor's CDN and into the HTML that Shopify ships on the first byte. Not all of it, necessarily; the last hundred reviews will do most of the job, particularly if they include the highest-rated and the most recent and a sample across the four- and three-star tail. The widget can stay on the page if the merchant likes the visual of stars-and-photos (most do). What matters is that somewhere above or below the widget, in plain server-rendered markup, there's a semantic list of articles, each one with a date, an author handle, a rating, and the actual paragraph the customer wrote.

That argument lives in reviews are language not inventory in the abstract. The grid above is the concrete version of the same point: the cell is empty because the language is in JavaScript, and the cell fills up the moment the language moves into HTML the crawler can read on the first hop.

The technical lift is small. Every review platform we've looked at exposes a JSON endpoint for the corpus. A Shopify theme can call that endpoint at request time, walk the response, render the articles into the product template. One afternoon of theme work in most cases, sometimes less, occasionally a day if the merchant wants to also pre-cache the response and serve it from the edge.

A year from now, the merchants whose grids are full won't be the ones who picked a prettier widget. They'll be the ones who quietly shipped a different page.

The closing turn

Look, we don't really blame the widget vendors for being widget vendors. They ship the thing they were built to ship, which is a piece of UI: stars, a count, a photo carousel, a verified-buyer badge. That was the brief in 2015 and that's still the brief on most merchant onboarding calls in 2026. The brief was, on its own terms, met.

What's changed since 2015 isn't the brief. It's the second audience nobody wrote a brief for. The crawlers came online quietly over the past two years and they read whatever HTML the server hands them on the first request, and whatever they carry away is what later gets quoted in some buyer's answer in some other context the merchant never sees. That second audience was always implicit in the widget's job. Now it's the larger of the two, and it's the one the widget is least equipped to serve.

If you haven't yet run the curl against your own store, you don't really know which side of that equation you're sitting on. So go do it. One terminal command, your bestselling product URL, three crawlers in turn. Grep the response for your highest-rated review's most distinctive line. If it isn't there (and we'd guess it isn't) you've just seen exactly what an answer engine sees when it comes to read your store. Whatever you decide to do next lives in the gap between that result and what your buyer sees in the browser.

If any of this reads like something your store could use,write to us.

We will write back.

Corrections

corrections@better-reviews.com

Mistakes are listed at the foot of the page when found.