An AI filler for Google Forms. It reads the questions, answers them using your own context so the result sounds like you, and writes the answers into the real form controls. You review and edit everything before anything is filled.
Chrome Manifest V3 · bring your own API key · no server, no build step, no analytics
| Question type | Behaviour |
|---|---|
| Short answer / Paragraph | Typed into the field |
| Multiple choice | Clicks the matching option |
| Checkboxes | Clicks every matching option |
| Dropdown | Opens the menu and clicks the match |
| Linear scale / Grid | Row → column mapping |
| Date | YYYY-MM-DD, split into month / day / year |
| Time | HH:MM plus AM/PM |
| Questions with images | Photos, diagrams and formulas are sent to the model |
| File upload | Detected and flagged — cannot be automated |
Every answer shows next to the question on the page, so you can see exactly what will be submitted:
There is no build step and no dependencies. You load the folder directly.
-
Download this repository — Code → Download ZIP, then extract it. Or:
git clone https://github.com/nullstacks/google-forms-copilot.git
-
Open
chrome://extensionsin Chrome, Edge, Brave or any Chromium browser. -
Turn on Developer mode (top-right toggle).
-
Click Load unpacked and select the
google-forms-copilotfolder. -
Pin the extension to the toolbar.
On first install the setup page opens by itself. It walks you through choosing a provider, testing the connection, writing your context, and picking preferences. Everything is stored locally and restored on every launch, so you only do this once.
Why "Load unpacked" and not the Web Store? This extension is published as source. You can read every line of what runs with your API key. Chrome will show a "developer mode extensions" notice at startup; that is expected for side-loaded extensions.
Gemini has a genuinely free tier — no credit card, no trial that expires. This is the recommended way to start.
Video walkthrough: How to Get API Key for Google Gemini (2026)
- Go to aistudio.google.com and sign in with a normal Google account.
- Accept the terms if prompted.
- In the left sidebar click Get API key (sometimes shown as API Keys).
- Click Create API key.
- If asked, pick or create a Google Cloud project. The default is fine — a free tier project is created for you.
- Copy the key. It looks like
AIza…and is shown once. - Paste it into Form Copilot's setup page under API key.
Click the Gemini preset on the setup page. It fills in:
| Field | Value |
|---|---|
| API base URL | https://generativelanguage.googleapis.com/v1beta/openai |
| Model | models/gemini-3.5-flash-lite |
| API key | your AIza… key |
Then click Test connection. You should see Connected. The model replied: {"ok":true}.
- Free-tier requests are rate limited per minute and per day. If you hit a limit
you get a
429error; wait a minute and retry. Normal form filling uses one request per form, so the limits are rarely a problem in practice. - Google may use free-tier inputs to improve their products. Do not paste secrets or sensitive personal data into your context, and do not use a free key on confidential forms.
- Free tier does not guarantee access to every model. If
models/gemini-3.5-flash-liteis unavailable on your key, click Fetch on the setup page to list what your key can actually reach, then pick from the dropdown. - The key is sent only to
generativelanguage.googleapis.com. It stays inchrome.storage.localon your machine.
Any OpenAI-compatible endpoint works. The setup page has presets for these:
| Provider | API base URL | Notes |
|---|---|---|
| Gemini | https://generativelanguage.googleapis.com/v1beta/openai |
Free tier, see above |
| OpenAI | https://api.openai.com/v1 |
Paid, sk-… key |
| OpenRouter | https://openrouter.ai/api/v1 |
Many models, some free |
| Local server | http://127.0.0.1:8787/v1 |
Anything exposing /v1/chat/completions |
For a self-hosted or other endpoint, type its base URL. Chrome will ask for host permission the first time — approve it, or nothing will load.
Click Fetch next to the Model field. It asks the endpoint for its model list and fills the ▾ dropdown. Pick one from there. If the endpoint reports no models, type the name manually — that is normal for some local servers.
Image reading needs a model that accepts image input. Gemini 1.5/2.x/3.x, gpt-4o,
gpt-4o-mini and most recent OpenRouter vision models qualify. If you pick a
text-only model, turn Read question images off in Settings to avoid errors.
-
Open a Google Form — the
/viewformlink or a publishedforms.glelink, not the edit view. -
Click the Form Copilot pill in the bottom-right corner. Or click the toolbar icon to open the side panel.
-
Write your context. This is the part that makes answers correct:
I'm Pushkar, a final-year CS student in Pune. My email is pushkar@example.com. Skills: JavaScript, Python, React, Postgres. Two years of freelance work. For rating questions, answer 4 out of 5. For "how did you hear about us", answer LinkedIn. -
Click Generate answers (or
Ctrl/Cmd+Enter). -
Review them. Each row shows the answer, a status badge, and a short note when the model made an assumption.
-
Click Fill form. Answers go into the real controls and ✓ badges appear on the page.
-
Submit the form yourself. The extension never submits anything.
Click Edit under any answer, change it, then click Done or click away. Click Fill form again to push the edit. Options → Reset form fields clears what was filled.
Three steps, shown on first install. Reopen any time from the extension's setup link.
| Step | What it asks |
|---|---|
| 1 | Provider, API base URL, key, model — with a live connection test |
| 2 | Your context, with Student / Job seeker / Feedback templates |
| 3 | Answer tone, image reading, auto-fill |
Settings are saved as you go and restored on every launch. Toggles in the Settings sheet apply immediately — no Save required.
content script ──scan──▶ normalized question JSON (+ image descriptors)
│
panel builds a prompt with your context
│
background worker → POST /chat/completions
│
JSON { answers, notes } parsed & normalized
│
content script ◀──apply── clicks / typing on the real form controls
| File | Role |
|---|---|
content/content.js |
Parses the form by ARIA roles; fills it; draws the badge layer |
background.js |
Owns every network call; runs the MAIN-world dropdown helper |
panel/ |
The UI — side panel or embedded iframe on the form page |
onboarding/ |
First-run setup |
lib/core.js |
Prompt building, JSON repair, per-type answer normalization |
Dropdowns must be driven from the page's own realm. Google's Material dropdown
ignores synthetic events created in a content script's isolated world, even though the
identical gesture works from the page. Dropdown filling is therefore delegated to the
service worker, which injects into the MAIN world with
chrome.scripting.executeScript. Radio buttons and checkboxes accept ordinary
synthetic clicks and need none of this.
Google Forms enforces Trusted Types, so new Function(...) and eval are blocked
in the page. The injected helper is passed as a real function reference, never as
source text.
Options are read before asking. Dropdown choices and image labels are collected from the DOM at scan time and included in the prompt, so the model picks from real options instead of inventing plausible-looking ones.
- Context and settings live in
chrome.storage.localon your machine. - The only network calls are to the API base URL you configure, plus the form's own Google hosts for reading question images.
- No analytics, no telemetry, no third-party hosts.
- Form contents are sent to your chosen provider as part of the prompt. Read the provider's data policy; for sensitive forms use a local model.
"Reload needed" — the extension was installed or updated after the form tab opened. Reload the form tab.
"Open a Google Form" — the tab is not on docs.google.com/forms/…. Edit URLs
(/forms/d/…/edit) are read-only by design; open the preview link instead.
Connection test fails with 401 / 400 — wrong key, or the base URL is missing
its /v1 (or /v1beta/openai for Gemini). Check that the model name exists on your
key by clicking Fetch.
429 errors — you are rate limited. On Gemini's free tier this is per-minute; wait
and retry. Consider a lighter model.
A required question got no answer — the panel lists it in red. Add the missing fact to your context and regenerate, or edit the answer by hand.
Dropdown says "would not open" — Google's menu needs the form tab to be active. The extension brings it forward and retries automatically; if it still fails, click the dropdown once yourself and fill again.
Nothing happens on "Fill form" — Google changed its DOM. Open DevTools, confirm
options still carry role="radio" / role="checkbox", and adjust the selectors in
content/content.js → analyzeBlock.
Radio options will not clear — a selected radio cannot be un-selected by any gesture; that is standard HTML semantics. Reset clears checkboxes and text, reports how many radios are stuck, and offers to reload the page.
No build, no bundler, no node_modules for the extension itself. Edit files and click
the reload icon on chrome://extensions.
node test/core.test.js # 32 unit tests — no browser neededThe browser suites need puppeteer-core and Chrome for Testing. Consumer Chrome
137+ refuses --load-extension, so the regular Chrome binary will not work.
npx @puppeteer/browsers install chrome@stable --path ./browsers
PPT=./node_modules/puppeteer-core \
CHROME=./browsers/chrome/*/chrome-*/chrome.exe \
node test/mock-e2e.js| Suite | Covers |
|---|---|
core.test.js |
JSON repair, per-type normalization, prompt building |
mock-e2e.js |
All 8 question types against a local mimic of the Forms DOM |
onboarding-e2e.js |
First-run setup, persistence, settings survival |
combo-e2e.js |
Model dropdown, close button, provider presets |
e2e.js |
Full extension against a live Google Form and a live model |
vision-e2e.js |
Image collection and visual question answering |
vision-ab.js |
A/B: same quiz answered with images off vs on |
test/e2e.js takes a form URL as its first argument. Screenshots land in
test/screenshots/.
| Permission | Why |
|---|---|
sidePanel |
Show the assistant beside the form |
storage |
Keep your settings and context locally |
tabs |
Find the form tab, focus it for dropdowns, reload on request |
scripting |
Run the dropdown helper in the page's own realm |
Host permission is limited to Google Forms and the four listed API providers. Any other endpoint prompts once.
MIT — see LICENSE.




