We built a brand-neutral AI grant agent demo for Northbridge Health Foundation that turns seeded grant records into reasoned first drafts in about 25-30 seconds per click at roughly 6 cents per draft. It gives fundraising leaders a safe, private way to evaluate AI-assisted grant writing before wiring it to live data.
Grant agent automation is: a focused system that ingests grant records, applies organizational context, and returns a structured, review-ready draft with transparent pass or fail reasoning.
This is a named client case study of a case-study demo. It was a proof-of-concept we built, not a live deployment. The same build applies directly to real nonprofit teams because the workflow, costs, and safety gates are identical.
The problem it solves
A fundraising team evaluating AI for grants needs to see real drafts on realistic opportunities without exposing private funder data or credentials. Slideware does not convince program leads or boards. A safe, hands-on demo with clear costs and latency does.
| Workflow | Manual review and drafting | Demo-assisted drafting |
|---|---|---|
| Discovery | Staff scans sites and PDFs, copies criteria | Seeded example records show requirements and notes |
| Drafting | Blank page, inconsistent structure | Consistent structure with single-source prompt |
| Eligibility | Ad hoc go or no-go calls | Explicit pass or fail reasoning per record |
| Cost per draft | Staff time every attempt | ~$0.06 per draft at observed model pricing |
| Turnaround | Hours to days | 25-30 seconds per draft |
| Data risk | Real funders and links in play | Brand-neutral, invented private funders for safety |
According to Instrumentl, writing a typical grant application can take on the order of 80-200 hours depending on complexity (source: https://www.instrumentl.com/blog/how-long-does-it-take-to-write-a-grant). A demo that proves structure and fit before full writing materially reduces false starts.
How the automation works
The demo runs as a small web app with a single drafting endpoint and a single-source prompt. Seeded grants include both pass and fail examples so reviewers can see confident rejections as well as drafts. The serverless endpoint keeps API keys off the client bundle and enforces a short timeout to bound latency and cost.
- Seeded grant dataset: A curated JSON file with 9 example opportunities, intentionally mixing eligible and ineligible cases. Private funders are invented to avoid misattribution. Each record carries brief notes used as context.
- Single-source prompt file: One authoritative prompt module used by both the live API route and the offline cache. Edits to tone or structure propagate everywhere.
- Serverless drafting proxy (accent): A backend route that accepts a single grant payload and calls the model provider. Keys live in encrypted env vars. No client-side SDK usage, so nothing sensitive ships to the browser.
- UI harness: A simple selector and Draft Application button. The app displays loading state, then a styled draft with section headings and an eligibility verdict.
Step-by-step: how to build it
1) Scaffold the demo app with a fixed base path
Create a lightweight React app and pin the public path so it can live under a demos hub. Keep the demo small so it ships in hours, not weeks.
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
base: '/demo/grant-agent/', // required for a subpath deploy
build: { outDir: 'dist/grant-agent' }
})Gotcha: client calls to your API route must be root-relative ("/api/draft"). The Vite base setting does not rewrite absolute paths.
2) Centralize the writing style in one prompt module
A single-source prompt keeps tone and structure consistent across the app and the API route.
// src/lib/prompt.js
export const grantPrompt = ({ orgName, mission, voice }) => `
You are drafting a first-pass application for ${orgName}.
Voice: ${voice}. Goal: be factual, concise, and donor-aligned.
Write: 1: Eligibility summary. 2: 3-5 tailored goals. 3: Measurement plan.
4: Budget sketch without new numbers. 5: Risks and mitigations. 6: Closing.
Constraints: never invent dollar figures or dates not provided.
Organization mission: ${mission}
`;Gotcha: keep the prompt in one file and import it in both client previews and the API route. Dual sources drift fast.
3) Add a serverless draft endpoint that hides provider keys
The endpoint reads a grant record, builds a prompt, calls your provider, and returns a structured draft. Keep timeouts under a minute.
// api/draft.js (serverless runtime)
import { grantPrompt } from '../src/lib/prompt.js'
export default async function handler(req, res) {
try {
const { grant, org } = await req.json()
const prompt = grantPrompt(org)
const body = {
model: process.env.AI_MODEL || 'default-mini',
messages: [
{ role: 'system', content: 'You write grant drafts. Be precise.' },
{ role: 'user', content: `${prompt}\n\nGrant record:\n${JSON.stringify(grant)}` }
]
}
// Call your AI provider through a server-side fetch
const r = await fetch(process.env.AI_COMPLETIONS_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.AI_API_KEY}`
},
body: JSON.stringify(body)
})
if (!r.ok) throw new Error(`Upstream error ${r.status}`)
const data = await r.json()
res.status(200).json({ draft: data })
} catch (e) {
res.status(500).json({ error: e.message })
}
}Gotcha: never import a provider SDK in the browser for demos. Keys will leak in the bundle or through devtools.
4) Seed pass and fail examples to prove judgment
Populate a small JSON file with realistic fields. Include at least two examples that clearly fail your eligibility rules to showcase confident rejections.
// src/data/grants-seed.json
[
{
"id": "nbhf-education-01",
"name": "Community Health Education Mini-Grant",
"eligibility": { "region": "Metro", "focus": ["health", "education"] },
"notes": "Small awards supporting health workshops at libraries."
},
{
"id": "private-funder-99",
"name": "Innovation Challenge",
"eligibility": { "region": "National", "focus": ["biotech"] },
"notes": "Invented private funder for demo safety. Intentionally a poor fit."
}
]Gotcha: treat private funders as invented for demos. It avoids brand confusion and keeps reviewers focused on output quality, not access.
5) Call the drafting route and show an honest loading state
Wire the UI to the serverless route and render drafts with a clear pass or fail flag. Set expectations for a 25-30 second round trip.
// src/pages/Demo.jsx
async function draft(grant, org) {
const r = await fetch('/api/draft', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ grant, org })
})
if (!r.ok) throw new Error('Draft failed')
return r.json()
}Gotcha: cap serverless function duration and surface a friendly retry if a draft runs long. Perceived speed matters in stakeholder demos.
6) Gate access and pin costs before sharing
Use an access scope check and a short list of allowed emails. Keep the AI key and model name in encrypted environment variables.
// src/lib/access.js
export function canAccess(email) {
const allow = (import.meta.env.VITE_ALLOW_EMAILS || '').split(',')
return allow.includes(email)
}Gotcha: send gated links only. Demo keys and costs should not be exposed to broad traffic.
Where it gets complicated
Never put model keys in the browser. Early attempts to use a client SDK invariably surface keys in bundles or devtools. Keep a thin serverless proxy and audit the build for stray strings before sharing.
Root-relative API calls with a subpath app. A demos hub often serves multiple apps under subpaths. Keep API calls root-relative. The Vite base setting does not rewrite absolute URLs.
Keep eligibility fields stable. UI components expect consistent field names. Renaming an eligibility property can quietly break pass or fail labeling. Treat the seed schema as an API contract.
Plan for timeouts and perceived latency. Drafts typically return in 25-30 seconds. Set function timeouts around a minute and show honest, branded loading states so stakeholders stay with the flow.
Deliberately seed failures. Teams learn as much from confident rejections as they do from good drafts. Include ineligible examples to demonstrate the system will not force-fit every opportunity.
What this actually changes
For a foundation or nonprofit team, this demo compressed the evaluation loop from meetings about AI to hands-on runs that show tone, structure, and eligibility calls in under a minute per attempt. It let nontechnical stakeholders test voice edits by changing a single prompt file and see the change propagate instantly.
Observed demo economics and UX were straightforward: roughly 6 cents per draft at the chosen model tier and about 25-30 seconds of latency per run. As a next step, wiring to a real opportunity feed and a lightweight review queue is incremental work because the serverless proxy and prompt are already proven.
External context: Instrumentl estimates that a typical grant application can take on the order of 80-200 hours to prepare depending on complexity, so a reliable pre-draft pass helps teams avoid spending those hours on poor-fit opportunities (source: https://www.instrumentl.com/blog/how-long-does-it-take-to-write-a-grant).
Frequently asked questions
Is this a live deployment or a demo?
This was a case-study demo we built for Northbridge Health Foundation, not a live deployment. The workflow, safety gates, and costs match what we ship in production, so it maps directly to real nonprofit teams.
How do you keep provider API keys safe in demos?
Keys never reach the browser. The app calls a serverless route that holds encrypted environment variables. We also audit bundles for stray strings and gate demo access so links are not publicly shareable.
Can we use our real grants database instead of seeded examples?
Yes. The demo uses a seeded JSON file to protect privacy. In production we add a small adapter that reads your real source of truth and applies the same prompt and proxy pattern.
What does it cost to run?
In the demo we observed roughly 6 cents per draft and 25-30 seconds of latency per run on the selected model tier. Your actual cost depends on model choice and average draft length. Infrastructure is minimal.
How fast can this go live for a nonprofit team?
We typically ship a private demo in days, then wire a review queue and your opportunity feed in a short follow-on. Because the prompt and proxy are already proven, productionizing is mostly plumbing and access.
If you want a safe, hands-on pilot that your team can click through in minutes, we have shipped this exact pattern. See our related walkthrough on automating grant drafting for nonprofits, or talk with us about a scoped pilot under document automation. When you are ready to evaluate this for your org, book a 15 minute call.
Want us to build this for you?
15-minute discovery call. No pitch. We tell you what to automate first.
Book a Discovery Call