Every grant application asks for roughly the same things: what your organisation does, who is on the team, what you have achieved so far, how much money you need and what you will do with it. Every funder asks for them in a different form, with different field names, different character limits and a different portal. If you apply to ten programmes a quarter, you type your company description ten times and your incorporation date ten times, and you still miss a deadline because the eleventh call was buried on a page you did not know to check.

That is the problem we set out to work on. This post is about the product decisions and the browser-extension mechanics behind it, including the parts that do not work yet. It is written for developers who are curious how form-filling extensions behave on real-world pages, not as a product tour.

The GrantSnap homepage: a live funding catalog, with the headline "Same grant. Two founders."

Why discovery and application are two different problems

Most grant tools stop at discovery: a database of calls with filters. That is useful, but a list of 300 open programmes is not an application. The expensive part comes after you find the call, when you open the funder's portal and start copying from last quarter's document.

We split the job into three steps and built one surface for each:

  1. Find the call. A catalog of grants, fellowships, accelerators, VC programmes, competitions and scholarships, pulled from a few hundred sources across 35+ countries and refreshed continuously. It lives on the web dashboard and is filterable by type, sector and region. Many people first meet a call through our newsletter, Startup911, which handles discovery; GrantSnap is the execution side.
  2. Draft the answers. The user builds one profile (legal name, what they do, location, registration, stage, team bios) and uploads existing documents such as a deck, a budget or a work plan. For each opportunity, a model drafts answers from that profile.
  3. Fill the form. A Chrome extension puts those drafts into the funder's own form in the user's browser. The user reviews each field and presses the funder's submit button.

The third step is the one that needed a browser extension, so that is what the rest of this post is about. The whole thing is GrantSnap; the catalog on the homepage is public if you want to see the first step.

Why an extension, not a copy-paste dashboard

Funder portals are not APIs. There is no standard schema for a grant application, and most portals do not want automated submissions. The only place the answers can go is the form on the funder's page, typed by the applicant. A dashboard that generates text still leaves the applicant switching tabs and pasting forty fields.

A Chrome extension can read the form the user is already looking at and write into it, with the user watching. That keeps the funder's own submit button, session and validation in charge, which matters for the trust question we come to later.

We only ship for Chrome and only test on Chrome. Other Chromium browsers may load the extension, but we do not claim support, and other engines are not supported at all.

What the extension reads

The extension reads the visible form on the current page: field labels, question text, placeholders and the fields adjacent to them. It does not read other tabs, mail, or the rest of the browser. The questions it finds are sent to the user's own GrantSnap account so they can be matched against that user's profile; the account is the same one used on the dashboard, so an account is required, and an empty profile produces generic text rather than nothing.

For developers thinking about building something similar, Chrome's documentation on content scripts covers the model we rely on, where a script runs in the context of the page and can see the DOM but not the user's other activity.

What it writes, and what it refuses to touch

The drafts go into the fields the extension managed to map. Short text inputs, text areas and common select menus are the main supported cases. Four kinds of field are deliberately left to the human:

  • File uploads
  • Signatures
  • Payment fields
  • CAPTCHAs

And one action is never performed: submitting. The extension has no submit path. Whatever is in the form, the applicant presses the funder's own button. We made that a product rule rather than a setting because a wrong number in a budget field is the applicant's problem with the funder, and they need to have seen it.

Where it breaks: layouts, wizards and shadow DOM

This is the part DEV readers will recognise. Every portal is a different layout, and three patterns cause most failures:

  • Multi-step wizards that load questions through JavaScript one step at a time, and sometimes destroy the previous step's DOM when you advance. If the fill runs before the step has rendered, it finds nothing. The current mitigation is unglamorous: let the step finish loading, then run fill; if it still misses, reload the step and run again.
  • Shadow DOM components. Fields inside a shadow root are not visible to a naive querySelector on the document, and labels may live outside the root the input lives in. Some of these fill poorly today.
  • Non-DOM forms: image-based forms, canvas widgets and anything behind a login the extension cannot see. These do not fill at all.

When a common form fails, the fallback is the dashboard: the same draft is there as plain text and can be pasted by hand. That is not elegant, but it means a broken selector never blocks an application.

How drafting works, and why thin profiles give thin drafts

The model sees two things: the questions from the funder's page (or from a deeper scan of the opportunity on the dashboard) and the user's stored profile and uploads. It does not browse the web for information about the applicant and does not compute any hidden score of the funder. Drafts are generated with Google Gemini. The profile, documents and saved applications are stored on our servers (we use Supabase) so the dashboard and the extension stay in sync; we do not claim local-only processing, and the privacy policy lists the processors.

The consequence is simple and worth stating plainly: a sparse profile produces a guess, not a usable draft, and a field skipped in the profile tends to stay skipped on every later form. The single most useful thing a user can do is write a funder-style description once, rather than a slogan.

Review is the feature, not a disclaimer

Generated answers are a starting paragraph, not a finished one. Two review habits matter more than anything else in the extension:

  • Numbers. Budgets, headcount, incorporation dates, tax IDs and beneficiary counts should be checked against the source document before submission. The model can copy a figure from the wrong year.
  • Template language. Similar questions produce similar drafts, and reviewers of grant applications read hundreds of them; filler is easy to spot. Editing a draft down is usually better than adding to it.

Because the filled fields are plain text in the funder's form, the applicant can edit in place, or go back to the dashboard and edit the draft there.

What we would do next

  • Better handling of shadow-DOM and wizard-style portals, which is where most failures come from.
  • A clearer signal in the UI for "this field was filled from a thin profile", so the review effort goes where it is needed.
  • Support beyond Chrome, once the Chrome behaviour is stable.

What we learned

The interesting engineering was not the model. It was the boring part: reading forms that were never designed to be read, deciding what never to automate, and making the review step feel like the point of the product rather than a warning label. If you are building anything that writes into other people's forms, start from the list of things you will refuse to do; it shapes the rest.

If you maintain a funder portal and want to know what a form-filler sees on your page, or you have hit a layout we handle badly, I would like to hear about it in the comments.

Disclosure: this article was drafted with AI assistance from GrantSnap's product documentation and edited by the author.