WeWidget
🌐HTML / Static site guide

Embed Google Reviews on Any HTML Website

Two lines of HTML. Works in any static site, custom build, or framework that outputs HTML. No CMS, no plugin, no dependencies required.

Get your embed code →

7-day free trial · No card required

Who this guide is for

This guide covers adding WeWidget to any project that outputs standard HTML — without a specific CMS or website builder in the picture:

If you are using a specific platform like WordPress or Webflow, see the dedicated guides for those platforms — they cover the platform-specific editor steps.

Before you start

Step-by-step installation

  1. 1

    Get your embed code

    Sign up at wewidget.app/signup, connect your Google Business Profile, and copy your embed code from Dashboard → Widget → Embed Code. Your unique widget ID will appear in place of "YOUR-WIDGET-ID".

  2. 2

    Place the div where you want the widget

    In your HTML file, add the div element at the exact position in the document where you want the reviews to render. This is a standard block-level element — it can go inside any container, section, or div in your layout.

    <div data-review-widget="YOUR-WIDGET-ID"></div>
  3. 3

    Add the script tag

    Place the script tag before the closing </body> tag. This ensures the DOM is fully parsed before the script runs — no defer attribute required in this position. If you prefer to keep scripts in <head>, use the defer attribute instead (see placement options below).

    <script src="https://app.wewidget.app/widget.js"
      data-widget-id="YOUR-WIDGET-ID"></script>
    💡The script tag must include the data-widget-id attribute. This tells the loader which widget to render — without it, nothing will appear.
  4. 4

    Test locally and deploy

    Open the HTML file in a browser (via a local server, not file:// — see the troubleshooting note below) to confirm the widget is rendering. Then deploy to your hosting as normal.

Complete page example

For reference, here is the snippet placed in a minimal HTML document:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>My Business</title>
</head>
<body>

  <h2>What our customers say</h2>
  <div data-review-widget="YOUR-WIDGET-ID"></div>

  <!-- Script at end of body — DOM is ready, no defer needed -->
  <script src="https://app.wewidget.app/widget.js"
    data-widget-id="YOUR-WIDGET-ID"></script>
</body>
</html>

Script placement options

The script tag can go in two places. Both work — the choice affects whether you need to use the defer attribute:

✓ Recommended: before </body>

The DOM is fully parsed at this point, so the script can find the div element immediately. No additional attributes needed.

<div data-review-widget="YOUR-WIDGET-ID"></div>
<script src="https://app.wewidget.app/widget.js"
  data-widget-id="YOUR-WIDGET-ID"></script>

Alternative: in <head> with defer

The defer attribute delays script execution until after HTML parsing completes — functionally equivalent to placing it before </body>. Use this if your project convention keeps all scripts in <head>. Do not use async — it may execute the script before the div is in the DOM.

<!-- In <head> — preferred for performance-sensitive pages -->
<script src="https://app.wewidget.app/widget.js"
  data-widget-id="YOUR-WIDGET-ID"
  defer></script>

<!-- In <body> — wherever you want the reviews to appear -->
<div data-review-widget="YOUR-WIDGET-ID"></div>

Content Security Policy headers

If your site sets a Content-Security-Policy header, you need to allow app.wewidget.app in both script-src and connect-src. The script loads from that origin and makes fetch requests back to it to retrieve review data.

Content-Security-Policy:
  script-src 'self' https://app.wewidget.app;
  connect-src 'self' https://app.wewidget.app;

Add these directives to your existing CSP header — do not replace it entirely.

Troubleshooting

The div is in the HTML but nothing renders

Open the browser console. The most common causes: (1) the widget ID is still the placeholder — sign in to get your real ID; (2) the page is served via file:// rather than http:// — use a local server; (3) the script tag is placed before the div in the HTML and has no defer — the script runs before the div exists.

Script blocked — net::ERR_BLOCKED_BY_CLIENT or CSP error

A browser extension or Content Security Policy header is blocking the script. For ad blockers, you can't resolve this — it affects a small percentage of users. For CSP, add app.wewidget.app to your script-src and connect-src directives as shown above.

Widget renders locally but not on the live site

Verify your widget ID in the deployed HTML matches the one in your WeWidget dashboard. Check for any environment-specific code that might be swapping the ID. Also confirm the live site is not setting a CSP that blocks external scripts.

Widget renders but shows no reviews

Open the Network tab in DevTools and look for requests to app.wewidget.app. If the request returns a 401 or 404, your subscription may have lapsed or the widget configuration needs to be republished from the dashboard.

Frequently asked questions

Does it work on static site generators like Astro, Hugo, or Jekyll?
Yes. Any static site generator that outputs HTML files supports the WeWidget embed. Add the snippet to whichever layout or partial wraps the page where you want reviews to appear. For Hugo: layouts/_default/baseof.html. For Jekyll: _layouts/default.html. For Astro: any .astro component.
Can I use defer or async on the script tag?
Use defer if you prefer to put the script tag in <head> — it will execute after the HTML is fully parsed, which is equivalent to placing it before </body>. Do not use async: the async attribute executes the script as soon as it downloads, which may be before the div placeholder is in the DOM, causing the widget to not find its target.
Will it work if I open the HTML file directly with file://?
No. The widget script makes network requests that are blocked under the file:// protocol due to browser security restrictions. Serve the file via a local web server (e.g. npx serve, Python's http.server, or your dev tool of choice) to test locally.
My Content Security Policy is blocking the script — what do I add?
Add app.wewidget.app to both your script-src and connect-src directives. The script loads from https://app.wewidget.app/widget.js and makes requests back to the same origin to fetch review data.
Can I load the widget only when a user scrolls to it?
Yes — use an IntersectionObserver to dynamically create and append the script tag when the div enters the viewport. This defers the network request until the widget is about to become visible. The WeWidget script handles dynamic injection correctly.
The div is in the page but nothing renders — what should I check?
First, check the browser console for errors. Common causes: (1) wrong or placeholder widget ID — sign in to confirm your ID; (2) the script loaded before the div was in the DOM — move the script to after the div in the HTML; (3) a Content Security Policy is blocking the script — check the Network tab for blocked requests; (4) the page is served over file:// — use a local server instead.

Also works on

Prefer a step-by-step guide for a specific platform?

Ready to embed Google reviews on your site?

Two lines of HTML · No dependencies · Free trial