AutoApply

AutoApply Icon

AutoApply

A Chrome extension (Manifest V3) that fills job applications on any website from your profile, using Google Gemini with your own API keys. It fills; you review and submit.

Chrome Extension TypeScript Preact Gemini API License: GPL v3

Check it out! AutoApply on Chrome Web Store

Table of Contents

App Preview

AutoApply Popup AutoApply Setup Settings
AutoApply Behaviour Settings

Features

Install

Requirements: Node 20+ and Chrome/Chromium 120+.

git clone https://github.com/ExxML/AutoApply.git
cd AutoApply
npm install
npm run build          # produces dist/
  1. Open chrome://extensions.
  2. Turn on Developer mode (top right).
  3. Click Load unpacked and choose the dist/ folder.

The settings page opens on first install at the setup wizard.

Note: Other Chromium-based browsers that support Manifest V3 should also work, but only Chrome/Chromium is tested.

Get Gemini API keys

  1. Go to https://aistudio.google.com/apikey and create a key.
  2. In AutoApply → Setup (or AI (Gemini)), paste it with a label and click Add key. The key is checked by fetching the model list; invalid keys are rejected with Google’s error message.
  3. Add more keys if you hit rate limits. AutoApply rotates to the next healthy key automatically when one returns a quota or rate-limit error.

Rate limits apply per Google Cloud project, not per key. Keys created in the same project share one quota. To get more capacity, create keys in separate projects. Free tier limits vary by model; see Gemini API rate limits for up-to-date quotas.

Each key row shows a status chip: Healthy, Cooling down until 14:32, Daily quota used for <model> until 00:00 PT, Invalid key, or Model unavailable on this key. Daily quotas reset at midnight Pacific time.

Choose a model

The model list is fetched live with your key and shows only text-in/text-out models that support generateContent (no embedding, image, audio, live, TTS or Gemma models), newest-added first. A Flash-Lite model is preselected because it is fast and cheap; picking a model runs a quick validation call (✓/✗). You can also set an optional fallback model, used automatically when every key is exhausted for the primary model. Click Refresh list to re-fetch (it also refreshes automatically once a day).

The newest Gemini models are often under heavy load, and rejected requests may still use up your quota. If consistency matters to you, use a slightly less popular model as your primary or fallback.

Fill in your profile

[!NOTE] Your profile, documents and saved answers are stored in your browser’s local storage. Clearing your browser data or uninstalling AutoApply deletes them, so keep a backup with Data → Export JSON (tick Include documents to back up your files too).

How filling works

  1. Click Fill this page in the popup or press Alt+Shift+F. AutoApply never starts on its own; it scans the page (including iframes and shadow DOM) only when you ask.
  2. Instant pass (no network): name, email, phone, address and links are matched from your profile; questions you answered before (saved answers) fill immediately.
  3. Everything else goes to Gemini in one batched call. It picks options by meaning (e.g. “willing to relocate = yes” → “I am willing to relocate”), and custom dropdowns and typeaheads are operated one at a time.
  4. Open-ended questions (“Why do you want to work here?”) are drafted by Gemini from your profile, résumé and the job description, respecting word/character limits, and marked as AI drafts.
  5. Multi-step applications: when the next step appears, click Fill this page (or press Alt+Shift+F) again. AutoApply does not watch the page between fills.
  6. The panel at the bottom right shows progress, the model used, and a Needs you list; click a row to jump to the field. Re-run and Stop are there too. Press Alt+Shift+W to expand or collapse it.
  7. When you answer a flagged field yourself, AutoApply offers to save the answer for future applications (see Saved answers in settings).

Badge meanings

Badge Meaning
Green ✓ Filled from your profile or a saved answer (“You”/”Saved” once you answered it yourself)
Blue AI Filled by Gemini’s semantic match (hover for the profile fields used and the chosen option)
Purple AI draft AI-written essay — review it. Click the tag to save it as a reusable answer
Yellow Needs you Unknown, low confidence, a consent/acknowledgement box, a sensitive field, or the AI declined. Hover for the reason and any suggestion
Orange Check The page shows something different from what was entered
Red Failed Could not be filled

Required consent and attestation boxes (privacy notice, terms, attestations) are ticked automatically by default; turn off Auto-accept required consents in Behavior to have them flagged instead. Optional consents (contact about other jobs, talent community, marketing) are set separately: auto-decline (default), auto-accept, or flag for you.

YOLO mode

Turn on YOLO mode in the popup (set it up under Settings → YOLO mode) and AutoApply finds new postings and applies to them by itself while the browser is open. It works in a hidden page, so nothing opens on screen.

Privacy

Your profile, documents and settings live only in this browser (chrome.storage.local). YOLO mode also keeps its application log and encrypted site passwords there; it reads job boards logged out, and reads verification emails only while a run waits for one. To answer questions, the extension sends your profile, résumé text, saved answers and the page’s field labels/job description to Google Gemini under your own API keys; there is no AutoApply server, analytics or telemetry. API keys stay in the extension’s background worker — web pages and content scripts never see them, they are masked after entry, and exports exclude them unless you tick Include API keys.

Limitations

Troubleshooting

How It Works

User clicks "Fill this page" (or presses Alt+Shift+F)
        │
        ▼
Content script scans the page, iframes and shadow DOM for fields
        │
        ▼
Instant pass (no network): profile values and saved answers filled
        │
        ▼
Remaining fields sent in one batch → background service worker
        │   Adds profile + résumé text, calls Gemini with a healthy key
        ▼
Gemini returns a decision per field: fill / essay / consent / needs you
        │
        ├── fill  → value entered, then verified against the page
        └── essay → drafted in a follow-up Gemini call, then entered
        │
        ▼
Badges + bottom-right panel show results; user reviews and submits

Development

npm run build       # type-check + production build → dist/
npm run lint        # eslint + prettier --check
npm test            # unit tests (Vitest + happy-dom)
npm run test:e2e    # build, then end-to-end tests with the unpacked extension and a mocked Gemini
npm run test:live   # build, then a smoke test against the real Gemini API

End-to-end tests use Playwright’s bundled Chromium in its new headless mode (channel: "chromium"), which supports extensions, so no display server or xvfb is needed. Run npx playwright install chromium once. Fixture pages in test/fixtures are served on ports 5501 and 5502 (for a cross-origin iframe); test/mockGemini.ts intercepts generativelanguage.googleapis.com (including the service worker’s requests) and can simulate per-minute and daily 429s, limit: 0, 503s, invalid keys and slow responses.

Live smoke test (npm run test:live) runs semantic.html and plain.html against the real API and asserts the semantic selections (relocation, negatively phrased sponsorship, EEO decline). It is skipped unless GEMINI_API_KEY is set; GEMINI_MODEL overrides the model (default: the first Flash-Lite model in the live list).

# PowerShell
$env:GEMINI_API_KEY = "AIza..."; npm run test:live
# bash
GEMINI_API_KEY=AIza... npm run test:live

See DECISIONS.md for design choices and deviations from the specification.

License

This project is licensed under the GNU General Public License v3.0.