Google Sites embed code: a snippet that works

Google Sites runs your own HTML, CSS and JavaScript through Insert, Embed, Embed code. Keep everything in one snippet, with CSS in style tags and JavaScript in script tags, then publish.

Google Sites can run your own code on a page. Click Insert, then Embed, then the Embed code tab, and paste HTML with its CSS and JavaScript. Google's help gives two rules: JavaScript must be inside <script> tags, and CSS must be inside <style> tags.

Here is a snippet that follows both rules. Click the button, then edit the question and run it again.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Flashcard for a Google Sites embed</title>
<!-- CSS goes inside <style> tags -->
<style>
  body { margin: 0; padding: 20px; font-family: system-ui, sans-serif; background: #f4f5f7; }
  .card {
    max-width: 340px; margin: 0 auto; padding: 18px 20px; border-radius: 12px;
    background: #fff; box-shadow: 0 6px 20px rgba(0, 0, 0, .1);
  }
  .card p { margin: 0 0 14px; font-size: 18px; }
  .answer { color: #0f5132; font-weight: 600; }
  button {
    font: inherit; padding: 9px 16px; border: 0; border-radius: 8px;
    background: #1d4ed8; color: #fff; cursor: pointer;
  }
</style>
</head>
<body>
<div class="card">
  <p>What does CSS stand for?</p>
  <p class="answer" id="answer" hidden>Cascading Style Sheets</p>
  <button id="flip">Show answer</button>
</div>

<!-- JavaScript goes inside <script> tags -->
<script>
  const answer = document.getElementById('answer');
  const flip = document.getElementById('flip');

  flip.addEventListener('click', () => {
    answer.hidden = !answer.hidden;
    flip.textContent = answer.hidden ? 'Show answer' : 'Hide answer';
  });
</script>
</body>
</html>
A flashcard: one style block, a few lines of markup, one script. This is the shape an embed snippet should have.

The part from <style> down to the closing </script> tag is what you paste into Google Sites. The <head> around it is there so the same file also opens on its own.

How to add embed code to Google Sites

These steps follow Google's own help page for adding HTML, CSS or JavaScript to a site.

Insert, Embed, Embed code, then Next, Insert and Publish.
Insert, Embed, Embed code, then Next, Insert and Publish.
  1. On a computer, open the site in Google Sites.
  2. In the panel on the right, click Insert, then Embed.
  3. Click Embed code and paste your snippet.
  4. Click Next, then Insert. The code now sits in a box on the page.
  5. Click Publish at the top right. Visitors see your changes after you publish.

If you are not sure your snippet is ready, check it first in a plain browser tab. Save it as an .html file and open it. If it works there on its own, it carries everything it needs.

Keep the whole widget in one snippet

An embed often half-works because it still points at other files. On your computer, style.css and app.js sit next to the page. In the embed box there is no folder next to the code, so those relative paths find nothing.

Left: links to files that are not there, and loose CSS and JavaScript. Right: one self-contained snippet.
Left: links to files that are not there, and loose CSS and JavaScript. Right: one self-contained snippet.

Paste the contents of those files into the snippet instead:

<style>
  /* everything from style.css */
</style>

<div id="app">...</div>

<script>
  // everything from app.js
</script>

If you do load a file from somewhere else, use its full https:// address. MDN notes that on an HTTPS page, browsers block insecure http:// requests for scripts and styles.

Check your snippet before you paste it

This checker looks for the mistakes above: files referenced by a relative path, http:// addresses, and CSS or JavaScript left outside its tag. Load the broken example, then the fixed one, or paste your own code.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Embed code checker</title>
<style>
  body { margin: 0; padding: 16px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  label { font-weight: 600; font-size: 14px; }
  textarea {
    display: block; box-sizing: border-box; width: 100%; height: 170px; margin: 6px 0 10px;
    padding: 10px; border: 1px solid #cfd4dc; border-radius: 8px;
    font: 13px/1.45 ui-monospace, Consolas, monospace;
  }
  .row { display: flex; flex-wrap: wrap; gap: 8px; }
  button { font: inherit; font-size: 14px; padding: 8px 13px; border: 1px solid #cfd4dc; border-radius: 8px; background: #fff; cursor: pointer; }
  button.main { background: #1d4ed8; border-color: #1d4ed8; color: #fff; }
  ul { list-style: none; margin: 14px 0 0; padding: 0; }
  li { margin-bottom: 8px; padding: 9px 12px; border-radius: 8px; font-size: 14px; line-height: 1.4; overflow-wrap: anywhere; }
  li.bad { background: #fff1ec; color: #9a3412; }
  li.good { background: #e8f7ee; color: #0f5132; }
</style>
</head>
<body>
<label for="code">Paste the code you plan to put in Embed code</label>
<textarea id="code" spellcheck="false"></textarea>
<div class="row">
  <button class="main" id="check">Check it</button>
  <button id="load-bad">Broken example</button>
  <button id="load-good">Fixed example</button>
</div>
<ul id="out"></ul>

<script>
  const code = document.getElementById('code');
  const out = document.getElementById('out');
  const end = '</' + 'script>';  // split so this page's own script tag does not close early

  const broken = [
    '<link rel="stylesheet" href="style.css">',
    '.box { color: teal; }',
    '<div class="box" id="msg">Hello</div>',
    '<script src="http://example.com/app.js">' + end,
    "document.getElementById('msg').textContent = 'Hi';"
  ].join('\n');

  const fixed = [
    '<style>',
    '  .box { color: teal; }',
    '</style>',
    '<div class="box" id="msg">Hello</div>',
    '<script>',
    "  document.getElementById('msg').textContent = 'Hi';",
    end
  ].join('\n');

  // A URL with no scheme points at a file next to the page. An embed has no such folder.
  const isRelative = (url) => !/^(https?:|data:|mailto:|tel:|#|\/\/)/i.test(url.trim());

  function check() {
    const problems = [];
    // Parse the snippet without running it
    const doc = new DOMParser().parseFromString(code.value, 'text/html');

    doc.querySelectorAll('script[src], link[href], img[src]').forEach((el) => {
      const url = el.getAttribute('src') || el.getAttribute('href');
      if (isRelative(url)) problems.push('"' + url + '" is a file next to your page. Paste its contents into the snippet instead.');
      else if (/^http:/i.test(url)) problems.push('"' + url + '" uses http://. An https page blocks insecure scripts and styles. Use https://.');
    });

    // Text left over after removing script and style tags shows up as plain text
    doc.querySelectorAll('script, style').forEach((el) => el.remove());
    const loose = doc.body ? doc.body.textContent : '';
    if (/[\w-]+\s*\{[^}]*:[^}]*\}/.test(loose)) problems.push('CSS rules are outside a <style> tag, so they appear as text.');
    if (/(document\.|function\s*\(|=>|addEventListener|console\.)/.test(loose)) problems.push('JavaScript is outside a <script> tag, so it appears as text.');
    if (!code.value.trim()) problems.push('The box is empty.');

    out.innerHTML = '';
    (problems.length ? problems : ['No problems found. This snippet is ready to paste.']).forEach((msg) => {
      const li = document.createElement('li');
      li.className = problems.length ? 'bad' : 'good';
      li.textContent = msg;
      out.append(li);
    });
  }

  document.getElementById('check').addEventListener('click', check);
  document.getElementById('load-bad').addEventListener('click', () => { code.value = broken; check(); });
  document.getElementById('load-good').addEventListener('click', () => { code.value = fixed; check(); });
  code.value = broken;
</script>
</body>
</html>
Paste embed code and check it. The code is parsed, not run, and nothing leaves the page.

The checker reads the code with DOMParser, which builds a document without running its scripts.

It then removes every <script> and <style> element and looks at the text that is left. Anything that still looks like code there would appear on your site as plain words.

Embed by URL or embed code

The same Embed dialog takes either a web address or code. They behave differently.

Embed by URL Embed code
What you give it The address of a page HTML, with CSS and JavaScript
Where the content lives On the other website In your Google site
Can it fail to show? Yes, if that site refuses to be embedded Yes, if the code has a mistake
How you update it Change the other page Change the code and publish again

Google's help notes that some websites won't let you add their content, and suggests contacting the site's owner. A site does this with the X-Frame-Options header or the frame-ancestors rule of its Content Security Policy. Embedding a website in another page covers how framing works.

Your snippet is not the Sites page

Write the snippet as its own small page. It should style and script only its own elements, not reach for the Sites page around it.

Google's Arts & Culture help notes that to embed content into a Google Sites site, you permit embedding on the domain googleusercontent.com.

That points to your snippet being served from a different domain than the site itself. In practice, keep each widget self-contained, and do not try to change the Sites header, menu or theme from your script.

Full page embed

An embed does not have to be a box between other content. In the Pages panel, hover over Add and choose Full page embed.

The new page holds one embed, and you can enter a URL or click Embed code and paste HTML, just as with a box.

This fits a tool that needs the whole screen, such as a calculator or a quiz, while the rest of the site stays a normal Google site.

A finished widget: a class quiz

A short self-check quiz is a typical thing to put on a class or team site. This one marks answers in the page itself. It uses a form, but the submit handler calls preventDefault(), so nothing is sent anywhere.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Class quiz for Google Sites</title>
<style>
  body { margin: 0; padding: 16px; font-family: system-ui, sans-serif; background: #f4f5f7; color: #1d2330; }
  .quiz { max-width: 460px; margin: 0 auto; padding: 18px; border-radius: 12px; background: #fff; box-shadow: 0 6px 20px rgba(0, 0, 0, .08); }
  h2 { margin: 0 0 4px; font-size: 19px; }
  .meta { margin: 0 0 14px; font-size: 13px; color: #6b7280; }
  fieldset { margin: 0 0 12px; padding: 10px 12px; border: 1px solid #e1e4ea; border-radius: 9px; }
  legend { padding: 0 4px; font-weight: 600; font-size: 15px; }
  label { display: block; padding: 4px 0; font-size: 15px; cursor: pointer; }
  fieldset.right { border-color: #6cc08b; background: #f0faf3; }
  fieldset.wrong { border-color: #f0a58c; background: #fff5f1; }
  button { font: inherit; padding: 9px 16px; border: 0; border-radius: 8px; background: #1d4ed8; color: #fff; cursor: pointer; }
  button[type=reset] { background: #e5e7eb; color: #1d2330; margin-left: 6px; }
  #score { margin: 12px 0 0; font-weight: 600; }
</style>
</head>
<body>
<form class="quiz" id="quiz">
  <h2>Web basics quiz</h2>
  <p class="meta">Three questions. Your answers stay in this page.</p>

  <fieldset data-answer="b">
    <legend>1. Which tag holds JavaScript?</legend>
    <label><input type="radio" name="q1" value="a"> &lt;js&gt;</label>
    <label><input type="radio" name="q1" value="b"> &lt;script&gt;</label>
    <label><input type="radio" name="q1" value="c"> &lt;code&gt;</label>
  </fieldset>

  <fieldset data-answer="a">
    <legend>2. Which tag holds CSS rules?</legend>
    <label><input type="radio" name="q2" value="a"> &lt;style&gt;</label>
    <label><input type="radio" name="q2" value="b"> &lt;css&gt;</label>
    <label><input type="radio" name="q2" value="c"> &lt;meta&gt;</label>
  </fieldset>

  <fieldset data-answer="c">
    <legend>3. What does HTML stand for?</legend>
    <label><input type="radio" name="q3" value="a"> High Text Machine Language</label>
    <label><input type="radio" name="q3" value="b"> Hyperlink Text Mode Layout</label>
    <label><input type="radio" name="q3" value="c"> HyperText Markup Language</label>
  </fieldset>

  <button type="submit">Check answers</button>
  <button type="reset">Start again</button>
  <p id="score" aria-live="polite"></p>
</form>

<script>
  const quiz = document.getElementById('quiz');
  const score = document.getElementById('score');

  quiz.addEventListener('submit', (e) => {
    e.preventDefault();  // mark the answers here; nothing is sent anywhere
    const data = new FormData(quiz);
    let right = 0;
    quiz.querySelectorAll('fieldset').forEach((set, i) => {
      const ok = data.get('q' + (i + 1)) === set.dataset.answer;
      set.className = ok ? 'right' : 'wrong';
      if (ok) right++;
    });
    score.textContent = 'You got ' + right + ' of 3 right.';
  });

  quiz.addEventListener('reset', () => {
    quiz.querySelectorAll('fieldset').forEach((set) => set.className = '');
    score.textContent = '';
  });
</script>
</body>
</html>
Three questions, marked in place. Copy everything from the style tag to the end of the script into Embed code.
  • Answers in markup: each <fieldset> has a data-answer attribute, so adding a question means copying one block.
  • Marking: FormData reads the chosen radio buttons, and each fieldset turns green or orange.
  • Reset: the form's own reset button clears the choices, and one listener clears the colours.

If the quiz should save results somewhere, that needs a server or a form service. Embedding a Google Form is the simpler route there, and the Google Form embed guide explains it.

When it does not work

What you see Cause Fix
Code appears as text on the page CSS or JavaScript outside its tag Wrap CSS in <style> and JavaScript in <script>
No styles, or buttons do nothing The snippet points at style.css or app.js Paste those files into the snippet
A library from another site never loads Its address starts with http:// Use the https:// address
Visitors still see the old version The site was not published again Click Publish
An embed by URL stays empty That website does not allow embedding Contact its owner, or use a link instead
Some people cannot open the site The published site is set to Restricted Add them, or set it to Public under Share

For script errors that are not about Sites at all, HTML JavaScript not working goes through the usual causes.

A Google Sites embed is the right home when the widget belongs on a site you already run. Under Share, the published site is Restricted or Public, and visitors open the site address.

Left: the snippet becomes part of a published site. Right: the file itself becomes a link.
Left: the snippet becomes part of a published site. Right: the file itself becomes a link.

If you only need people to try one page, you do not need a site around it.

Paste the page into a NOS document and choose Create share link. HTML to link walks through it.

The page renders as written and its scripts run, so anyone with the link can click through the quiz without an account. If you change the code later, the same link shows the new version.

Questions people ask

Can Google Sites run JavaScript?

Yes, through an embed. Click Insert, then Embed, then Embed code, and paste your code. Google's help says JavaScript must be inside <script> tags and CSS inside <style> tags. Click Publish so visitors see it.

Why does my embed code show up as text on the page?

Part of the code sits outside a <script> or <style> tag. Anything outside those tags is treated as HTML, so a loose CSS rule or line of JavaScript is shown as plain words. Wrap each part in the right tag.

Can I embed a whole page instead of a box?

Yes. In the Pages panel, hover over Add and choose Full page embed. You can enter a URL there, or click Embed code and paste HTML, as with a normal embed.

Why will a website not embed by URL?

Google's help notes that some websites won't let you add their content to your site, and suggests contacting the website's owner. A site can refuse to be shown inside other pages with the X-Frame-Options header or the CSP frame-ancestors rule.

Who can see my embedded code?

Whoever can see the published site. Under Share, the published site is set to Restricted or Public. With Restricted, only the people and groups you add can open it.

Keep reading