Skip to content

afkhalid/ghostfill

Repository files navigation

GhostFill

Stop demoing with test123. Generate realistic, domain-aware form data in one click.

The Problem

Every team has this story. A PM is demoing to a client, and right there on the screen: "Cheeseburger" in the company name field, "asdf" for the email, and "John Doe" — the same John Doe — on every single record. QA tests with garbage. Designers screenshot forms full of "test123". There's no easy way to fill forms with realistic, context-appropriate data without writing seed scripts or maintaining test fixtures.

Before GhostFill:

First Name:    test
Last Name:     test
Email:         test@test.com
Company:       asdfasdf
Job Title:     fjdksl
Phone:         1234567890
Address:       123 test street

After GhostFill:

First Name:    Sarah
Last Name:     Mitchell
Email:         s.mitchell@northwind.com
Company:       Northwind Traders
Job Title:     Senior Account Executive
Phone:         +1 (312) 555-0187
Address:       401 N Michigan Ave, Chicago, IL 60611

One click. Any form. No seed scripts.

Who It's For

Developers install it — npm install ghostfill -D, one import, done. But the whole team benefits:

  • QA Engineers — fill forms with realistic edge cases instead of copy-pasting the same test data
  • Product Managers — demo to clients with professional-looking data, not "test123"
  • Designers — screenshot real-looking forms for decks and specs
  • Solution Architects — show realistic D365, Salesforce, or ERP data during workshops

Not Another Faker

faker.js fills your database. Browser autofill fills your data. GhostFill fills the form you're looking at — visually, with data that fits the context.

GhostFill faker.js Browser Autofill
Who uses it Anyone on the team Developers only Individual user
How it works Visual in-page UI Code library Browser feature
Data quality Domain-aware, contextual Random but typed Your personal data
Form detection Reads labels, selects, custom dropdowns N/A — you call it in code Standard inputs only
Domain presets D365, Healthcare, E-commerce, etc. Generic schemas N/A
Setup One import, zero config Write generation scripts Already there

Install

npm install ghostfill -D

Usage

Vanilla JS

import { init } from "ghostfill";

init();

React / Next.js

// app.tsx or layout.tsx
import { useEffect } from "react";

function GhostFill() {
  useEffect(() => {
    import("ghostfill").then((m) =>
      m.init({
        ai: {
          endpoint: "/api/ghostfill",
          provider: "openai",
        },
      })
    );
  }, []);
  return null;
}

// In your app:
{process.env.NODE_ENV === "development" && <GhostFill />}

Programmatic

import { fill } from "ghostfill";

await fill({ container: document.querySelector("form") });

How it works

  1. A ghost icon appears on the page (starts minimized)
  2. Click it to enter selection mode — hover and click a form area
  3. Click the sparkles button to fill all detected fields
  4. By default, generates random sample data locally (no API needed)
  5. Optionally enable AI mode in settings for context-aware data generation through your backend

Presets

Save prompt templates for domain-specific data:

  • D365 CE — Accounts, Contacts, Opportunities with CRM-realistic values
  • Healthcare — Patient intake, insurance, clinical forms
  • E-commerce — Products, orders, customer profiles
  • Automotive — Vehicle specs, service records, dealer info
  • Custom — Write your own prompt template for any domain

Presets are stored locally in the browser and sent as context to the AI provider.

Secure AI Setup

GhostFill no longer accepts provider API keys in the browser. To use OpenAI, xAI, or Moonshot safely, expose a backend route and keep provider credentials server-side.

Install a server-side SDK in your app:

npm install openai

Example Next.js route:

// app/api/ghostfill/route.ts
import OpenAI from "openai";
import {
  buildFillMessages,
  parseFillDataPayload,
  type GhostFillAIRequest,
  type Provider,
} from "ghostfill/server";

const clients: Record<Provider, OpenAI> = {
  openai: new OpenAI({
    apiKey: process.env.OPENAI_API_KEY,
  }),
  xai: new OpenAI({
    apiKey: process.env.XAI_API_KEY,
    baseURL: "https://api.x.ai/v1",
  }),
  moonshot: new OpenAI({
    apiKey: process.env.MOONSHOT_API_KEY,
    baseURL: "https://api.moonshot.ai/v1",
  }),
};

const models: Record<Provider, string> = {
  openai: process.env.GHOSTFILL_OPENAI_MODEL || "gpt-4o-mini",
  xai: process.env.GHOSTFILL_XAI_MODEL || "grok-4-fast",
  moonshot: process.env.GHOSTFILL_MOONSHOT_MODEL || "kimi-k2",
};

function isProvider(value: unknown): value is Provider {
  return value === "openai" || value === "xai" || value === "moonshot";
}

export async function POST(req: Request) {
  const body = (await req.json()) as Partial<GhostFillAIRequest>;

  if (!isProvider(body.provider) || !Array.isArray(body.fields)) {
    return Response.json({ error: "Invalid GhostFill request" }, { status: 400 });
  }

  const completion = await clients[body.provider].chat.completions.create({
    model: models[body.provider],
    messages: buildFillMessages({
      provider: body.provider,
      prompt: typeof body.prompt === "string" ? body.prompt : "",
      systemPrompt:
        typeof body.systemPrompt === "string" ? body.systemPrompt : undefined,
      fields: body.fields,
    }),
  });

  const content = completion.choices[0]?.message?.content || "";
  return Response.json(parseFillDataPayload(content));
}

This route supports all three providers, keeps secrets server-side, and only sends non-secret field metadata to the model. If you expose it outside local development, add your app's auth, rate limits, and request-size validation.

Settings

Click the gear icon to configure:

  • Highlight Colour — pick the selection overlay color
  • Use AI — toggle AI-powered fills when a secure backend route is configured
  • Provider — cycle between OpenAI, xAI, and Moonshot
  • Backend — shows the secure route or handler being used for AI fills
  • Presets — save prompt templates for domain-specific data (e.g. D365, healthcare); keep them non-secret because they are stored locally
  • Dark/Light theme — toggle with the sun/moon icon

Features

  • Zero config — works out of the box with random sample data
  • Secure by default — AI mode uses a backend route instead of browser-held provider keys
  • Shadow DOM — styles don't leak into your app
  • Framework-aware — uses native value setters so React/Vue/Angular pick up changes
  • Smart detection — labels from <label>, aria-label, placeholder, preceding siblings
  • Custom dropdowns — handles Headless UI Listbox, Radix Select, and other role="listbox" components
  • Draggable — drag the toolbar or minimized icon anywhere
  • Presets — save and reuse prompt templates
  • Dark/Light mode — matches your preference
  • Keyboard shortcutAlt+G to toggle

API

init(options?)

Initialize GhostFill and add the UI to the page.

init({
  ai?: {
    endpoint?: string,         // Same-origin backend route (default: "/api/ghostfill")
    requestFillData?: (request: GhostFillAIRequest) => Promise<FieldFillData[]>,
    provider?: "openai" | "xai" | "moonshot"
  },
  shortcut?: string,           // Keyboard shortcut (default: "Alt+G")
  systemPrompt?: string        // Custom system prompt to prepend
})

Returns { destroy: () => void } to remove the UI.

fill(params)

Programmatic fill without the UI.

await fill({
  container: HTMLElement,  // The element containing form fields
  prompt?: string,         // Optional prompt for AI mode
  ai?: {
    endpoint?: string,
    requestFillData?: (request: GhostFillAIRequest) => Promise<FieldFillData[]>,
    provider?: "openai" | "xai" | "moonshot"
  },
  provider?: "openai" | "xai" | "moonshot",
  systemPrompt?: string
})

Returns { filled: number, errors: string[] }.

MCP Server

GhostFill includes an MCP (Model Context Protocol) server so AI agents like Claude Code and Cursor can generate form data directly.

{
  "mcpServers": {
    "ghostfill": {
      "command": "npx",
      "args": ["ghostfill-mcp"]
    }
  }
}

Tools:

  • ghostfill_generate — Generate realistic fake data locally. No API key required.
  • ghostfill_generate_ai — Generate context-aware data via OpenAI, xAI, or Moonshot. Requires an API key.

Requires @modelcontextprotocol/sdk and zod as peer dependencies:

npm install @modelcontextprotocol/sdk zod

License

PolyForm Shield 1.0.0 — free to use, but you can't use it to build a competing product.

About

AI-powered form filler — select a block, detect fields, fill with AI-generated data

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors