Skip to content
Hazelsong is still being built.Skip to content
Hazelsong

Two lines

Testimonials on Elementor

The HTML widget, dragged where you want it.

Paste these two lines

Paste these two lines
<script src="https://hazelsong.com/widget/YOUR-SLUG.js?template=wall" async></script>
<div id="hazelsong-wall"></div>

Your slug is in your dashboard, with the tag ready to copy.

Where they go

  1. Open the page in Elementor.
  2. Drag the "HTML" widget into the section you want.
  3. Paste both lines into its Content box.
  4. Publish. Elementor's editor canvas may not run the script; the live page does.

Or let your coding agent do it

If an agent edits your site — Cursor, Claude Code, Lovable, Bolt or another — paste this into it. It carries the steps above for Elementor, keeps the id the script looks for, and tells the agent to change nothing else, add no other analytics, and show you the diff before anything is published. Replace YOUR-SLUG with your slug, or let the agent ask you for it; your dashboard, under Walls and widgets, has the same prompt with your slug already in it.

Paste this into your coding agent
Add the Hazelsong testimonial widget to this site. Make only the change described here.

What to add: these two lines. Keep the src and the id exactly as written. Where the page cannot hold a raw script tag, the instructions below say how to load the same src.

<script src="https://hazelsong.com/widget/YOUR-SLUG.js?template=wall" async></script>
<div id="hazelsong-wall"></div>

YOUR-SLUG is a placeholder. Before you change anything, ask me for my project's slug — it is in my Hazelsong dashboard, under Walls and widgets — and put it in place of YOUR-SLUG. Do not guess it.

The div with id="hazelsong-wall" is where the testimonials are drawn, so it goes where they should appear on the page. The script finds that element by its id: keep the id exactly as written, and use it once on a page. The script tag can sit next to the div or before </body>.

This site is built with Elementor. Hazelsong's instructions for Elementor:

1. Open the page in Elementor.
2. Drag the "HTML" widget into the section you want.
3. Paste both lines into its Content box.
4. Publish. Elementor's editor canvas may not run the script; the live page does.

Some of these steps may happen in Elementor's own editor rather than in files you can change. Do the ones you can, and tell me which ones are left for me to do; do not find another way around them, such as a plugin, a package or a different file.

Rules:
- Do not change anything else: no other files, no formatting, no renaming, no refactoring, no new dependencies.
- Do not add any other analytics, tracking, cookie or consent code.
- Do not change the src, the id or the attributes of the lines above, and do not install a package for Hazelsong: there is none.
- When you are done, show me the diff of every change you made, and wait for me to approve it before you commit, deploy or publish anything.

If it draws nothing

Open the page with ?hazelsong=debug added to its address and look in the browser's console. The widget says there why it drew nothing or counted nothing: no element to draw into, a layout that does not exist, nothing approved that your customers allowed on your website, a page that is not on your list of sites, a browser that says it is automated or is marked as yours, this month's delivery spent, or how a lift test placed that browser. It says this in that browser only and sends nothing anywhere.

If your site sends a Content-Security-Policy header, it has to allow the widget's addresses, or the browser blocks them without drawing anything. Add these to the directives you already have, each beside your own sources:

Content-Security-Policy, the widget's part
script-src https://hazelsong.com; connect-src https://hazelsong.com; img-src https://hazelsong.com https://*.public.blob.vercel-storage.com data:; media-src https://*.public.blob.vercel-storage.com; frame-src https://hazelsong.com https://www.youtube-nocookie.com https://player.vimeo.com https://www.loom.com; style-src 'unsafe-inline'
  • script-src — The widget and the ask dialog are each one script from this address.
  • connect-src — The testimonials are fetched from it, a video's address is asked for when somebody presses play, and the counts are sent to it.
  • img-src — Pictures and video stills are asked for at this address, which sends the browser on to storage; photographs uploaded through a form are served from storage directly. A photograph that arrived through the API with an address of its own is loaded from that address: allow https:, or turn photographs off with photos=0.
  • media-src — A recorded video plays from storage once somebody presses play.
  • frame-src — The ask dialog is a frame of the collection form, and a YouTube, Vimeo or Loom video is that platform's own player.
  • style-src — Each script adds one style element of its own; without this the widget is drawn with no styling.

If your project answers on a domain of your own (Starter and Pro), the two lines can load the widget from it instead: https://testimonials.yourdomain.com/widget/YOUR-SLUG.js. Everything it asks for then goes to that address, which serves your project and no other, and your policy names your domain where it named ours:

Content-Security-Policy, from your own domain
script-src https://testimonials.yourdomain.com; connect-src https://testimonials.yourdomain.com; img-src https://testimonials.yourdomain.com https://*.public.blob.vercel-storage.com data:; media-src https://*.public.blob.vercel-storage.com; frame-src https://testimonials.yourdomain.com https://www.youtube-nocookie.com https://player.vimeo.com https://www.loom.com; style-src 'unsafe-inline'

When the widget cannot draw on one of your pages — no element to draw into, drawn at no size, a layout that does not exist, an error while drawing — it also tells us that page's address, without its query and with anything that looks like an id or an email address cut out, and which of the four it was. Nothing about the reader. Your report's “Is anything broken?” then lists the page with the fix. So that a page reports each thing once a day, that report keeps a note in the visitor's browser, and it waits for the same consent answer as the lift test below: without it, nothing is kept or sent, and ?hazelsong=debug still says what went wrong.

What you already have

Each guide below is one of those places and Elementor together: how they come across, and where they go.

Collect one, and put it on Elementor

A form link, a customer who writes for a minute, and two lines on your page.