How I Built a Chrome Extension With Gemini and Claude: From UI to Code

“The best tools not only solve your problem – they change how you build everything.”

What is ImageSnatch and Why Did I Build It?

ImageSnatch is a Chrome extension that lets you extract and download every single image from any Google Docs document with one click.

No manual right-clicking, no messy screenshots, no more hunting through the DOM or snipping tool drama.

  • Instantly scan a Google Doc for images (even ones hidden in iframes or background layers)
  • Preview and select exactly which images you want
  • Download them all at once, or copy directly to your clipboard
  • Supports PNG, JPG, and WebP formatsauto-detects image resolution
  • Dead-simple popup UI, designed for speed
  • Secure: does everything locally, doesn’t send your data anywhere

Who’s it for?

  • Bloggers
  • Content creators
  • Researchers/Students
  • Anyone who needs to quickly re-use or cite visuals from Google Docs

I built ImageSnatch out of sheer frustrationGoogle Docs makes it a pain to save images. Now anyone can do it in seconds.

Get it live now (free):

👉 ImageSnatch Chrome Extension

Why Use Gemini and Claude for the Full Build?

I didn’t want “templates.” I wanted a real productfast.

AI workflows gave me two things:

  • UI inspiration and mockups before a single line of HTML
  • Code-level problem solving, refactoring, and debugging hints that actually stick

Gemini turned my rough UX notes into visuals I could use instantly in docs, pitches, or even first release versions. Claude helped me restructure buggy JavaScript and spot gaps even Chrome’s docs wouldn’t explain.

Step 1: Start With Real-World UX (Don’t Fake It)

I always begin with how real users will use my extension. Here’s my flow for ImageSnatchbefore even touching Gemini or Claude:

  • Open a Google Docs document
  • Click “ImageSnatch” in the Chrome toolbar
  • UI pops up: see thumbnails of all images
  • Either batch extract or copy images to clipboard
  • Let users select/deselect images, choose formats, get clean success feedback

This user journey became my first prompt.

Step 2: Gemini-Powered Design Mockups

I crafted direct, “no fudge” prompts for Gemini to get browser-ready UI images and mockups:

Chrome extension popup

Step 3: Code Smarter (Not Just Faster) With Claude

Design is half the battle.
The real war is in JS landwhere Chrome APIs, permissions, and weird Google Docs markup can break anything.

Whenever I hit a wall:

  • Gemini helped me visualize where the logic broke (bad overlays, missing buttons, stylistic clashes)
  • Claude got me past real bugs:
    • Weird permission errors or ⚡️”chrome.scripting.executeScript” not returning data
    • DOM scraping for images in iframes and backgrounds
    • Download failures, clipboard restrictions

My go-to strategy:

  • Drop the code into Claude: “Why aren’t images detected here?”
  • Get back concise suggestionsusually a refactor or edge-case scan.
selected thumbnails

Key Code Block: Multi-Method Image Detection

function scanForImagesFromCanvas() {
  const images = [];

  // 1. ModelChunk: Dig deep in Google JS data blobs.
  if (window.DOCS_modelChunk) {
    const dataStr = JSON.stringify(window.DOCS_modelChunk);
    const urlMatches = dataStr.matchAll(/(https?:\/\/[^"'\s\\]*(?:googleusercontent\.com|ggpht\.com)[^"'\s\\]*)/g);
    for (const match of urlMatches) {
      let url = match[1];
      url = url.replace(/\\u003d/g, '=').replace(/\\/g, '');
      images.push({ url: url, index: images.length });
    }
  }

  // 2. Iframe images: Hunt every iframe for undiscovered img tags.
  document.querySelectorAll('iframe').forEach(iframe => {
    try {
      const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
      iframeDoc.querySelectorAll('img').forEach(img => {
        if (img.src) images.push({ url: img.src, index: images.length });
      });
    } catch (e) {
      // Cross-origin? Get blocked? Move on.
    }
  });

  // 3. Background images: Some images hide in CSS, not HTML.
  document.querySelectorAll('*').forEach(el => {
    const bgImg = window.getComputedStyle(el).backgroundImage;
    if (bgImg && bgImg !== 'none') {
      const urlMatch = bgImg.match(/url\(['"]?([^'"()]+)['"]?\)/);
      if (urlMatch && urlMatch[1]) images.push({ url: urlMatch[1], index: images.length });
    }
  });

  return images;
}

Claude’s advice: Always check permissions, handle CORS errors, and never trust Google Docs not to change its markup tomorrow.

5 images downloaded
5 images downloaded

Step 4: Iterate FastDesign, Test, Debug, Ship

  • With Gemini, I could tweak my UI flow, swap button positions, and reduce visual clutter in minutes.
  • With Claude, “Why is Chrome not downloading images here?” actually led to new API calls and fallback mechanisms.

Deployment was just the last 5%. Most effort went into watching Gemini/Claude bounce off my ideas so I could release sooner, fail less.

Why You Should Build Extensions This Way

  • Gemini keeps your UI clean, practical, and user-focused.
  • Claude helps you break through coding hurdles you’d otherwise Google (unsuccessfully).
  • The combo gets you a shippable productnot just a cool GIF in Figma.

All my release images, mockups, and heavy code sections came out of this workflow.
Try it for your own Chrome extensiona real product, not just another “AI demo.”

Some Lessons I Learned

  • Always be specific in prompts. Vague = rework.
  • Code is contextGemini helps you see what users will actually experience.
  • Don’t neglect permissions, CORS, or the “hidden images” that make Google Docs a scrape nightmare.
  • Testing with both AI and real-world users beat perfect designs every time.
  • Ask Claude for help when you’re stucknot just for polish.

Conclusion

If you found this walkthrough useful, share it, leave a comment, or tag a friend trying to get AI working for them in real builds.

Follow me on Medium, X, and LinkedIn for hands-on guides and honest tech deep dives.

Want my favorite Gemini prompts, best extension code snippets, or more dev stories?
DM meI actually reply.

Leave a Comment