Platforms
Google reviews HTML embed: what the snippet really does
There is no Google reviews HTML code. Google does not publish a snippet you can paste on your own domain, and the iframe trick that half the internet suggests is blocked by a header on Google’s side, which we reproduced three times in a browser this morning. What does work in plain HTML is four lines: a stylesheet link, a script tag, one init call and an empty div, served by something that has already collected your reviews. This post measures exactly what those four lines cost, request by request, on a page with no CMS behind it.
We built that page by hand on 11 August 2026, loaded it in headless Chromium at 1280 pixels wide, and recorded every byte on the wire with the browser’s own network instrumentation. Then we tried the iframe routes, and let the browser tell us why they fail.
The iframe route is closed, and the browser says so out loud
The most common suggestion for “google review iframe” is to point an iframe at a Google URL and let Google draw your reviews. We tried the three URLs people actually use. All three were refused before a single pixel was drawn.
| Framed URL | What the browser did | Bytes of content |
|---|---|---|
search.google.com/local/reviews?placeid=… | Refused, X-Frame-Options: sameorigin | 0 |
google.com/maps/place/… | Refused, X-Frame-Options: sameorigin | 0 |
google.com/search?q=…+reviews | Refused, X-Frame-Options: sameorigin | 0 |
The console message is identical in each case: refused to display in a frame because it set
X-Frame-Options to sameorigin. Each frame kept its 644 by 404 pixel box on the page and stayed
empty. We confirmed the same header outside the browser with a plain request to each address, so it
is not a headless quirk, a cookie banner or a region thing. It is a response header, which means no
attribute you add to your iframe can override it. The frame is refused by the browser, not by your
code.
There is exactly one Google surface that permits framing, the Maps embed, and it is worth knowing
what you get if you reach for it as a substitute. We loaded a hand written page whose only content
was maps.google.com/maps?q=…&output=embed, and let it settle.
| Page under test | Requests | Bytes over the wire | Reviews shown |
|---|---|---|---|
| Google Maps embed iframe | 70 | 769,951 | 0 |
| Our reviews snippet, 20 reviews rendered | 9 | 227,603 | 20 |
Seventy requests, of which four map scripts alone are 91,209, 85,126, 75,465 and 71,780 bytes, plus a static map image at 59,775 bytes and three Google font files. Three and a third times the transfer of the whole page we are about to break down, to show a map. Not one review. If your goal is a review as a piece of readable text on your page, and something a language model can quote back, the map embed does not do that job at any price.
What the plain HTML embed actually costs
Here is the page we measured. Nothing but a heading, a sentence, and the snippet, served over HTTPS so the widget behaves exactly as it does on a customer domain.
<h1>What our customers say</h1>
<p>A hand written page. No CMS, no plugin, no build step.</p>
<div id="justreview-page"></div>
<script src="https://justreview.co/widget/justreview.js"></script>
<link rel="stylesheet" href="https://justreview.co/widget/justreview.css">
<script>
document.addEventListener('DOMContentLoaded', function () {
JustReview.initReviewsPage('YOUR_USER_ID', { /* your settings */ });
});
</script>
Nine requests, 227,603 bytes over the wire in total. The full waterfall, timed from the moment navigation started:
| Request | Bytes on the wire | Uncompressed | Started | Finished |
|---|---|---|---|---|
| The HTML document itself | 1,913 | 1,913 | 0 ms | 5.5 ms |
justreview.js | 129,010 | 488,265 | 16.1 ms | 119.7 ms |
justreview.css | 15,579 | 109,861 | 17.4 ms | 120.3 ms |
| API call, all reviews for this account | 4,595 | 12,448 | 139.9 ms | 185.8 ms |
4 × Nunito woff2 | 76,506 | 76,506 | 206.9 ms | 298.2 ms |
Read that table twice, because the shape of it is the whole argument. The document you wrote is 1,913 bytes. The library is 67 times bigger than your page, and the four font files the stylesheet pulls in are 76,506 bytes, a third of the total transfer, fetched only once the review text is on its way in. There is exactly one call to our API for the whole widget, it returns 12,448 characters of JSON containing 20 reviews, and it finishes 185.8 ms after navigation started.
The rendering timeline is short. The init call runs at 138.5 ms, the first node lands inside the container at 202.9 ms, and the container has height, meaning visible reviews, at 218.8 ms. On a second load in the same browser session the first pixels arrived at 109.8 ms. What ends up in that div is not decoration: 4,841 pixels tall, 20 review cards, 1,455 words of customer text, 299,533 characters of HTML that were not in your file.
That last number is the real trade. A hand coded page stays a hand coded page, 1,913 bytes of markup you can read in one screen, and the review content arrives at runtime from somewhere that keeps it fresh. Nothing to update when a review changes, no build step, no database.
One library, one call per widget
The second question people hit on a hand built site is what happens with more than one widget, since there is no plugin to manage it. We put a carousel and a full reviews list on the same page and measured again.
| Page | Requests | Wire bytes | Library downloads | API calls |
|---|---|---|---|---|
| One widget | 9 | 227,603 | 1 | 1 |
| Two widgets | 10 | 235,098 | 1 | 2 |
The library and stylesheet are fetched once, no matter how many widgets you initialise. Each init gets its own API call, and the second widget cost 7,495 bytes in total. So the honest rule for a static site is: paste part one exactly once per page, repeat only the init call and the container. Two copies of the script on one page is the failure mode to avoid, and it is the one our own documentation warns about.
The two ways this quietly does nothing
Both of these produce the same symptom, an empty page and a clean looking console, and we walked into the first one ourselves while setting up this very measurement.
The container id does not match the init call. Our first run had a div called
justreview-reviews-page while the function looks for justreview-page. Result: the library
downloaded, the stylesheet downloaded, the API answered with all 20 reviews, 150,715 bytes crossed
the wire, and the page rendered zero pixels. No error, because from the library’s point of view
nothing went wrong, it simply had nowhere to draw. Every platform post we have written this month
found live sites in exactly that state, so check the id character by character before you suspect
anything else.
The script never runs at all. On a hand written page this is usually a copy that lost part two,
or an init call sitting above the library, or a script that a build tool moved. The tell is the
network panel: if justreview.js is there and the API call is not, your init never executed. If both
are there and the page is empty, you are in the first case.
Neither of these is specific to hand written HTML, which is why the same three parts appear in our universal install guide and in the platform guides. On a CMS the parts hide in a plugin screen or a theme file, as we found when we traced the same snippet through WordPress. On a static page they are all visible in one file, which makes debugging faster than anywhere else.
Why run our snippet on a hand coded page
The reason to use JustReview here is that everything in this post was measurable from outside the product. Nine requests, one API call, one container, no server side code, nothing that runs on your host and nothing to keep updated. That is the whole install: embedding reviews on your own site is the same four lines whether the page is a static file, a landing page or the last thing left of an old site, and it puts Google, Facebook and marketplace reviews in one list, which no Google surface will do for you at all. Because the reviews render as real text in the DOM, they are readable by anything that reads your page, which is not true of anything you could have framed.
Two caveats, and the second one is about our own pricing. The transfer is real: 227 KB with fonts, so put the list where it earns that, one section of its own rather than three copies across a page, and keep the badge for pages that just need a signal. And the full reviews list we measured here is a Pro feature. The free plan gives you the floating badge with 100 stored reviews from Google and Facebook and no card, the carousel starts on Plus at 9 € a month, and the list plus the review form sit on Pro. The split is on our pricing page.
If your site is hand written HTML, the cheapest first test is to create an account, connect Google, and paste the badge into your page before anything else. The badge needs no container div, so it cannot fail the way the id mismatch above fails, and it tells you in one page load whether your domain and your snippet are in order. Add the list once you know the plumbing works. It is running further down this page, drawn by the same four lines.
FAQ
Is there an official Google reviews HTML embed code?
No. Google publishes no HTML snippet that renders your reviews on your own domain. The Places API returns at most five reviews and forbids storing them, the Business Profile API needs you to own the profile and returns JSON rather than markup, and the only iframe Google offers is the Maps embed, which shows a map. Everything you can paste as plain HTML comes from a third party that has already done the collecting and the rendering.
Why can I not just put Google reviews in an iframe?
Because the browser refuses to draw the frame. We loaded three Google URLs in iframes on 11 August 2026, a Maps place page, a local reviews page and a search result. All three were blocked with the same console error: refused to display because it set X-Frame-Options to sameorigin. The frames stayed empty and zero bytes of content arrived. This is a header on Google's side, so no attribute on your iframe changes it.
How much does a reviews snippet add to a page?
On a hand written page we measured on 11 August 2026: 9 requests and 227,603 bytes over the wire, of which the HTML document itself was 1,913 bytes. The library was 129,010 bytes compressed, the stylesheet 15,579, one API call 4,595, and four web font files 76,506 bytes together. The first review pixels appeared 218.8 ms after navigation started.
Do two widgets on one page load the library twice?
No. We put a carousel and a full reviews list on the same page: one request for the script, one for the stylesheet, and one API call per widget. The second widget cost 7,495 extra bytes, not another 129 KB. The rule is the opposite for the library itself, though: paste it exactly once, because two copies of the script on one page can break rendering.