Gemini Canvas quiz: turn it into a link students can open

A quiz built in Gemini Canvas is a web page. Copy its code, paste it into NOS, and your students get an ordinary link that works on any phone or laptop.

A quiz made in Gemini Canvas is a small web page, so it can become a link that opens in any browser. Open the Code view in Canvas and copy all of it. Paste it into a NOS document and choose Create share link.

Students open that address on a phone, tablet or laptop. The Canvas share link has limits that matter in a classroom, covered below. Here is a self-checking quiz of the kind Canvas produces, running as a plain page. Answer it and press the button.

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>Water cycle quiz</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; padding: 14px; font-family: system-ui, sans-serif; background: #eef3f8; color: #1d2330; }
  .quiz { max-width: 560px; margin: 0 auto; background: #fff; border-radius: 14px; padding: 18px 18px 20px; box-shadow: 0 2px 10px rgba(0,0,0,.08); }
  h1 { font-size: 20px; margin: 0 0 4px; }
  .sub { margin: 0 0 14px; font-size: 14px; color: #5b6472; }
  fieldset { border: 0; padding: 0; margin: 0 0 16px; }
  legend { font-weight: 700; font-size: 16px; line-height: 1.35; padding: 0; margin-bottom: 8px; }
  label { display: block; padding: 10px 12px; margin-bottom: 6px; border: 1px solid #d5dbe4; border-radius: 8px; font-size: 15px; cursor: pointer; }
  label:has(input:checked) { border-color: #2563eb; background: #eff5ff; }
  label.right, label.right:has(input:checked) { border-color: #16a34a; background: #e8f7ee; }
  label.wrong, label.wrong:has(input:checked) { border-color: #ea580c; background: #fff1e6; }
  input { margin-right: 8px; }
  .why { display: none; font-size: 14px; color: #374151; margin: 2px 0 0; }
  .why.show { display: block; }
  button { font: inherit; font-weight: 700; padding: 11px 18px; border: 0; border-radius: 8px; background: #2563eb; color: #fff; cursor: pointer; }
  button.ghost { background: #e5e9f0; color: #1d2330; margin-left: 8px; }
  #result { margin-top: 14px; font-size: 17px; font-weight: 700; min-height: 24px; }
</style>
</head>
<body>
<main class="quiz">
  <h1>Water cycle: quick check</h1>
  <p class="sub">Pick one answer for each question, then press Check answers.</p>
  <form id="quiz"></form>
  <button type="button" id="check">Check answers</button>
  <button type="button" id="reset" class="ghost">Start again</button>
  <p id="result" aria-live="polite"></p>
</main>

<script>
  // To fix a question, edit its text below. "answer" is the position of the right option, counting from 0.
  const QUESTIONS = [
    { q: 'What do we call water turning from liquid into vapour?',
      options: ['Condensation', 'Evaporation', 'Precipitation'], answer: 1,
      why: 'Heat from the sun turns liquid water into vapour.' },
    { q: 'Clouds form when water vapour cools and becomes tiny droplets. This is called...',
      options: ['Condensation', 'Evaporation', 'Collection'], answer: 0,
      why: 'Cooling vapour condenses into droplets.' },
    { q: 'Which of these is a form of precipitation?',
      options: ['Fog on a window', 'Snow', 'A puddle drying'], answer: 1,
      why: 'Rain, snow, sleet and hail fall from clouds.' }
  ];

  const form = document.getElementById('quiz');

  function build() {
    form.innerHTML = '';
    QUESTIONS.forEach((item, i) => {
      const set = document.createElement('fieldset');
      const legend = document.createElement('legend');
      legend.textContent = (i + 1) + '. ' + item.q;
      set.appendChild(legend);
      item.options.forEach((text, j) => {
        const label = document.createElement('label');
        const input = document.createElement('input');
        input.type = 'radio';
        input.name = 'q' + i;
        input.value = j;
        label.appendChild(input);
        label.appendChild(document.createTextNode(text));
        set.appendChild(label);
      });
      const why = document.createElement('p');
      why.className = 'why';
      why.textContent = item.why;
      set.appendChild(why);
      form.appendChild(set);
    });
    document.getElementById('result').textContent = '';
  }

  document.getElementById('check').addEventListener('click', () => {
    let score = 0;
    let unanswered = 0;
    QUESTIONS.forEach((item, i) => {
      const set = form.children[i];
      const picked = form.querySelector('input[name="q' + i + '"]:checked');
      set.querySelectorAll('label').forEach((l) => l.classList.remove('right', 'wrong'));
      if (!picked) { unanswered++; return; }
      const labels = set.querySelectorAll('label');
      labels[item.answer].classList.add('right');
      if (Number(picked.value) === item.answer) score++;
      else picked.parentNode.classList.add('wrong');
      set.querySelector('.why').classList.add('show');
    });
    const out = document.getElementById('result');
    out.textContent = unanswered
      ? 'Answer all ' + QUESTIONS.length + ' questions first (' + unanswered + ' left).'
      : 'You got ' + score + ' of ' + QUESTIONS.length + '.';
  });

  document.getElementById('reset').addEventListener('click', build);
  build();
</script>
</body>
</html>
A three-question quiz that marks itself. Questions live in one list near the top of the code.

Make it with AI

Ask Canvas for a page that stands on its own. The prompt below keeps the questions in one list, which makes fixing them easy later. You can paste it into ChatGPT or Claude too.

Make a self-checking quiz as one HTML page.
Topic: [your topic], [number] multiple-choice questions for [age or level].
Put all questions in one JavaScript list at the top: question text,
the options, the number of the right option, and a one-line explanation.
Show a Check answers button, mark each question right or wrong,
and show the score. Mobile friendly, large tap targets.
Do not use any outside libraries, images, fonts or sign-in.
Do not save data anywhere.

Then check the result before you send anything:

  • Every answer key. Read each question and confirm the marked answer is the right one. An AI quiz can be confidently wrong.
  • Phone width. Resize the preview narrow. Options should be easy to tap.
  • No extras. Canvas apps can use Gemini-powered features and shared data. A copied page cannot, so the quiz must run on its own.

A one-question-at-a-time version. A long page of questions is a lot to scroll on a phone. Change one line of the prompt: "Show one question at a time with a Next button and a progress bar." The result looks like this.

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>One question at a time</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; padding: 14px; font-family: system-ui, sans-serif; background: #f3efe8; color: #1d2330; }
  .card { max-width: 520px; margin: 0 auto; background: #fff; border-radius: 14px; padding: 18px; box-shadow: 0 2px 10px rgba(0,0,0,.08); }
  .bar { height: 8px; border-radius: 4px; background: #e5e9f0; overflow: hidden; margin-bottom: 14px; }
  .bar i { display: block; height: 100%; width: 0; background: #2563eb; transition: width .25s; }
  .count { font-size: 13px; color: #5b6472; margin: 0 0 6px; }
  h1 { font-size: 19px; line-height: 1.35; margin: 0 0 12px; }
  .opt { display: block; width: 100%; text-align: left; font: inherit; font-size: 16px; padding: 13px 14px; margin-bottom: 8px; border: 1px solid #d5dbe4; border-radius: 10px; background: #fff; cursor: pointer; }
  .opt.right { border-color: #16a34a; background: #e8f7ee; }
  .opt.wrong { border-color: #ea580c; background: #fff1e6; }
  .opt:disabled { cursor: default; color: inherit; }
  .note { min-height: 40px; font-size: 14px; color: #374151; margin: 4px 0 10px; }
  .next { font: inherit; font-weight: 700; padding: 11px 20px; border: 0; border-radius: 8px; background: #2563eb; color: #fff; cursor: pointer; }
  .next[hidden] { display: none; }
  .final { font-size: 22px; font-weight: 700; margin: 8px 0; }
</style>
</head>
<body>
<main class="card" id="card"></main>

<script>
  // Fix a question here: change the text, keep the quotes and commas.
  const CARDS = [
    { q: 'A fraction with the same top and bottom number equals...', options: ['0', '1', '10'], answer: 1, note: 'Three thirds is one whole.' },
    { q: 'Which fraction is the largest?', options: ['1/2', '1/4', '1/8'], answer: 0, note: 'The smaller the bottom number, the bigger each piece.' },
    { q: '2/4 is the same amount as...', options: ['1/2', '1/4', '2/2'], answer: 0, note: 'Divide top and bottom by 2.' }
  ];

  const card = document.getElementById('card');
  let i = 0, score = 0;

  function show() {
    if (i >= CARDS.length) {
      card.innerHTML = '<div class="bar"><i style="width:100%"></i></div><p class="final"></p><button class="next" id="again">Try again</button>';
      card.querySelector('.final').textContent = 'You got ' + score + ' of ' + CARDS.length + '.';
      document.getElementById('again').addEventListener('click', () => { i = 0; score = 0; show(); });
      return;
    }
    const c = CARDS[i];
    card.innerHTML = '<div class="bar"><i></i></div><p class="count"></p><h1></h1><div id="opts"></div><p class="note" aria-live="polite"></p><button class="next" hidden>Next</button>';
    card.querySelector('.bar i').style.width = (i / CARDS.length * 100) + '%';
    card.querySelector('.count').textContent = 'Question ' + (i + 1) + ' of ' + CARDS.length;
    card.querySelector('h1').textContent = c.q;
    const opts = card.querySelector('#opts');
    const next = card.querySelector('.next');
    c.options.forEach((text, j) => {
      const b = document.createElement('button');
      b.type = 'button';
      b.className = 'opt';
      b.textContent = text;
      b.addEventListener('click', () => {
        opts.querySelectorAll('.opt').forEach((o) => { o.disabled = true; });
        opts.children[c.answer].classList.add('right');
        if (j === c.answer) score++; else b.classList.add('wrong');
        card.querySelector('.note').textContent = c.note;
        next.hidden = false;
        next.textContent = i === CARDS.length - 1 ? 'See my score' : 'Next';
      });
      opts.appendChild(b);
    });
    next.addEventListener('click', () => { i++; show(); });
  }
  show();
</script>
</body>
</html>
One question per screen with a progress bar. Questions are in a list near the top of the code.

Google's help page for Canvas says that when you share, you copy a g.co/gemini/share link. It also says shared links only open in gemini.google.com, and that shared Canvas content cannot be opened in the Gemini mobile app.

Accounts matter too. Google's Workspace announcement said business and education users cannot share Canvas content. Google's admin help says public link sharing is off by default until an administrator turns it on. As of October 2026, check with your Google admin.

The Canvas share link compared with a page link, as described in Google help pages in October 2026.
The Canvas share link compared with a page link, as described in Google help pages in October 2026.

A page link sidesteps both points. It is a normal web address, so a phone browser opens it directly.

  1. In the Canvas panel, click Code, select all the text and copy it.
  2. Paste it into a NOS document. The quiz renders and its script runs, so try it yourself first.
  3. Choose Create share link and copy the address. HTML to link walks through it.
  4. Post the link where your students already look.
From the Canvas code to a link students open in a browser.
From the Canvas code to a link students open in a browser.

Anyone with the link can open the page without an account, and nobody can edit it by opening it. If a phone shows an attached file as text instead of a quiz, see opening an HTML file on a phone.

Google Classroom's help says teachers can attach links to assignments, so the same address can go in an assignment. For paper handouts, put the link in a QR code. QR code link explains why that stays easy to update.

Fix a question without starting over

Quizzes get fixed: a typo, a wrong answer key, a question that is too hard. Two ways work, and neither changes the link.

Fix a question in Canvas by selecting it, or in the code by editing one line.
Fix a question in Canvas by selecting it, or in the code by editing one line.

In Canvas. Click Select & ask at the bottom right of the Canvas panel, select the question text with the cursor, type what you want changed and press Enter. Google's help describes this for apps. Then copy the new code.

In the code. If your quiz keeps questions in one list, find the question and retype it. Fix the answer number as well. Then paste the code into the same NOS document. The same link shows the new version.

Ways to share the quiz compared

Canvas share link HTML file attached Page link
Opens in gemini.google.com in a browser Depends on the phone Any browser
Work or school account Depends on the admin setting Not involved Not involved
Fix a question later Edit in Canvas Send a new file Edit, paste again, same link

As of October 2026. Google can change Canvas sharing, so check its help page.

When it does not work

Symptom Cause Fix
Share is greyed out or missing in Canvas Work or school account, or the admin has not turned on public links Ask your admin, or copy the code and use a page link
Students see code, not a quiz The file was sent as an attachment and opened as text Send the link, not the file
Quiz shows right answers on a wrong pick The answer number is off by one Answer numbers start at 0, so fix the number
Nothing happens on the button A line was lost when copying Copy all of the Code view again
Images or fonts are missing They came from another website, which the page blocks Ask for a version without outside images
Score is not recorded anywhere The quiz marks itself in the browser only Ask students to tell you the score, or use a tool for graded tests

If you want to build the quiz by hand instead, HTML quiz shows the structure, and HTML quiz code with score gives a full working example. For the preview you see inside Gemini, Gemini HTML code preview explains how it differs from a real browser.

Questions people ask

Can students open a Gemini Canvas quiz with the Canvas share link?

Only in a browser. Google's help page says shared Canvas links only open in gemini.google.com and cannot be opened in the Gemini mobile app. As of October 2026, a work or school account may not offer Share at all, because public link sharing is an admin setting that is off by default.

Why is the Share button greyed out in Canvas?

Google's Workspace announcement said business and education users cannot share Canvas content, and the admin help page says public link sharing is off until an administrator turns it on. Check with your school's Google admin. The copy-the-code route below does not use the Share button.

How do I fix a wrong question after I have sent the link?

Fix it in Canvas with Select & ask, or edit the question text in the code, then paste the updated code into the same NOS document. The link you already sent shows the new version.

Can I see which student got which score?

No. The quiz marks itself in the student's browser and shows the score to that student only. NOS does not record who opened a link or what they answered. For a graded test, use a tool built for it, and use this for practice.

Can students see the answers by looking at the code?

Yes, because the page needs the answer key to mark itself. Treat a quiz like this as practice or a self-check, not as a test that counts toward a grade.

Keep reading