Back to skills
SkillHub ClubResearch & OpsFull StackBackend

google-image-search

Search and download images via Google Custom Search API with LLM-powered selection. This skill should be used when finding images for articles, presentations, research documents, or enriching Obsidian notes with relevant visuals. Supports simple queries, batch processing from JSON config, automatic config generation from terms, and full note enrichment with automatic image insertion below headings.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
45
Hot score
91
Updated
March 20, 2026
Overall rating
C2.7
Composite score
2.7
Best-practice grade
B77.6

Install command

npx @skill-hub/cli install glebis-claude-skills-google-image-search

Repository

glebis/claude-skills

Skill path: google-image-search

Search and download images via Google Custom Search API with LLM-powered selection. This skill should be used when finding images for articles, presentations, research documents, or enriching Obsidian notes with relevant visuals. Supports simple queries, batch processing from JSON config, automatic config generation from terms, and full note enrichment with automatic image insertion below headings.

Open repository

Best for

Primary workflow: Research & Ops.

Technical facets: Full Stack, Backend.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: glebis.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install google-image-search into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/glebis/claude-skills before adding google-image-search to shared team environments
  • Use google-image-search for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: google-image-search
description: Search and download images via Google Custom Search API with LLM-powered selection. This skill should be used when finding images for articles, presentations, research documents, or enriching Obsidian notes with relevant visuals. Supports simple queries, batch processing from JSON config, automatic config generation from terms, and full note enrichment with automatic image insertion below headings.
---

# Google Image Search Skill

Search for images using Google Custom Search API with intelligent scoring and LLM-based selection.

## When to Use

- Finding images to illustrate technical articles or research
- Adding visuals to presentations
- Enriching Obsidian notes with relevant images
- Batch image search for multiple topics
- Generating image search configs from plain text lists

## Requirements

- Google Custom Search API key and Search Engine ID
- OpenRouter API key (for LLM selection)
- llm CLI installed at `/opt/homebrew/bin/llm`

Store credentials in `.env`:
```
Google-Custom-Search-JSON-API-KEY=your_key
Google-Custom-Search-CX=your_cx
OPENROUTER_API_KEY=your_openrouter_key
```

## Modes of Operation

### 1. Simple Query

Search for a single term:

```bash
python3 ~/.claude/skills/google-image-search/scripts/google_image_search.py \
  --query "neural interface wearable device" \
  --output-dir ./images \
  --num-results 5
```

### 2. Batch Processing

Process multiple queries from JSON config:

```bash
python3 ~/.claude/skills/google-image-search/scripts/google_image_search.py \
  --config image_queries.json \
  --output-dir ./images \
  --llm-select
```

### 3. Generate Config from Terms

Create JSON config from a list of terms using LLM:

```bash
python3 ~/.claude/skills/google-image-search/scripts/google_image_search.py \
  --generate-config \
  --terms "AlterEgo wearable" "sEMG electrodes" "BCI headset" \
  --output my_queries.json
```

### 4. Enrich Obsidian Note

Extract visual terms from note, find images, and insert below headings:

```bash
python3 ~/.claude/skills/google-image-search/scripts/google_image_search.py \
  --enrich-note ~/Brains/brain/Research/neural-interfaces.md
```

This mode:
1. Detects Obsidian vault and attachments folder
2. Uses LLM to extract visual-worthy terms from note
3. Searches for images for each term
4. Downloads best images to attachments folder
5. Inserts image embeds below relevant headings
6. Creates backup before modifying note

## Key Options

| Option | Description |
|--------|-------------|
| `--query TEXT` | Simple single query |
| `--config FILE` | JSON config for batch |
| `--generate-config` | Generate config from `--terms` |
| `--enrich-note FILE` | Enrich Obsidian note |
| `--output-dir DIR` | Where to save images |
| `--urls-only` | Return URLs only, no download |
| `--llm-select` | Use LLM to pick best image (default: on) |
| `--no-llm-select` | Disable LLM selection |
| `--num-results N` | Results per query (default: 5) |
| `--dry-run` | Show what would be done |

## JSON Config Format

Each entry supports:

```json
{
  "id": "unique-id",
  "heading": "Display Heading",
  "description": "Context for what image to find",
  "query": "Google search query",
  "numResults": 5,
  "selectionCriteria": "What makes a good image",
  "requiredTerms": ["must", "have"],
  "optionalTerms": ["bonus", "terms"],
  "excludeTerms": ["stock", "clipart"],
  "preferredHosts": ["official-site.com"],
  "selectionCount": 2
}
```

See `references/api_config_reference.md` for full documentation.

## Scoring System

Images are scored based on:
- **Required terms**: -80 if missing, +30 if all present
- **Optional terms**: +5 per match
- **Exclude terms**: -50 per match
- **Preferred hosts**: +25 if trusted, -5 if unknown
- **MIME type**: +5 for PNG/JPEG, -10 for GIF
- **Resolution**: +10 for high res, -10 for low res
- **File size**: -5 if very small

## LLM Selection

After scoring, LLM picks the best image from top candidates based on:
- Title and URL metadata
- Scoring reasons
- Selection criteria

The LLM evaluates authenticity, clarity, and relevance for technical audiences.

## Obsidian Integration

When in an Obsidian vault:
- Auto-detects vault root via `.obsidian` folder
- Uses configured attachments folder (default: `Attachments`)
- Generates Obsidian-style embeds: `![[image.png|alt text]]`
- Creates backup before modifying notes

## Script Files

| File | Purpose |
|------|---------|
| `google_image_search.py` | Main entry point |
| `api.py` | Google Custom Search API |
| `config.py` | Credentials and config handling |
| `download.py` | Image download with magic bytes |
| `evaluate.py` | Keyword-based scoring |
| `llm_select.py` | LLM selection and term extraction |
| `obsidian.py` | Vault detection and enrichment |
| `output.py` | Markdown output generation |


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### references/api_config_reference.md

```markdown
# JSON Config Reference

This document describes the JSON configuration format for batch image searches.

## Config Structure

The config file is a JSON array of entry objects:

```json
[
  { /* entry 1 */ },
  { /* entry 2 */ },
  ...
]
```

## Entry Fields

### Required Fields

| Field | Type | Description |
|-------|------|-------------|
| `query` | string | The Google search query |

### Recommended Fields

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `id` | string | auto | Unique identifier, used for filenames |
| `heading` | string | query | Display heading in output |
| `description` | string | - | Context about what image to find |
| `numResults` | int | 5 | Number of results to fetch (1-10) |

### Selection Fields

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `selectionCriteria` | string | - | What makes a good image for this topic |
| `selectionCount` | int | 2 | How many top candidates to consider for LLM selection |

### Scoring Fields

| Field | Type | Description |
|-------|------|-------------|
| `requiredTerms` | string[] | Terms that MUST appear in title/URL (missing = -80 score) |
| `optionalTerms` | string[] | Bonus terms that improve score (+5 each) |
| `excludeTerms` | string[] | Terms to penalize (-50 each) |
| `preferredHosts` | string[] | Trusted domains (+25 if match) |

### API Fields

| Field | Type | Description |
|-------|------|-------------|
| `imgType` | string | Image type: clipart, face, lineart, stock, photo, animated |
| `rights` | string | License filter: cc_publicdomain, cc_attribute, cc_sharealike, cc_noncommercial, cc_nonderived |
| `safe` | string | SafeSearch: active, moderate, off (default: active) |
| `fileType` | string | File type filter: jpg, gif, png, bmp, svg, webp, ico, raw |
| `siteSearch` | string | Restrict to specific site |

## Example Config

```json
[
  {
    "id": "alterego-device",
    "heading": "AlterEgo Silent Speech Interface",
    "description": "Wearable device for silent speech recognition using sEMG signals",
    "query": "AlterEgo MIT silent speech interface wearable",
    "numResults": 5,
    "selectionCriteria": "Real photo of device being worn, not concept art",
    "selectionCount": 3,
    "requiredTerms": ["AlterEgo"],
    "optionalTerms": ["MIT", "wearable", "speech"],
    "excludeTerms": ["stock", "illustration", "concept"],
    "preferredHosts": ["mit.edu", "media.mit.edu"],
    "safe": "active"
  },
  {
    "id": "semg-electrodes",
    "heading": "Surface EMG Electrodes",
    "description": "Medical-grade surface electrodes for muscle signal detection",
    "query": "surface EMG electrodes medical grade",
    "numResults": 5,
    "selectionCriteria": "Clear photo showing electrode placement on skin",
    "requiredTerms": ["electrode"],
    "optionalTerms": ["EMG", "surface", "medical"],
    "excludeTerms": ["clipart", "diagram"]
  }
]
```

## Scoring Algorithm

Each image is scored based on config criteria:

```
Base score: 0

Required terms:
  All present: +30
  Any missing: -80

Optional terms:
  +5 per match

Exclude terms:
  -50 per match

Preferred hosts:
  Match: +25
  No match: -5

MIME type:
  JPEG/PNG: +5
  GIF: -10

Resolution:
  >= 600x400: +10
  < 300x300: -10

File size:
  < 20KB: -5
```

## LLM Selection

After scoring, top `selectionCount` candidates are sent to LLM with:
- Title
- URL
- Host
- Score
- Scoring reasons
- Selection criteria

LLM returns JSON:
```json
{
  "chosen_index": 1,
  "explanation": "Best shows actual device in use"
}
```

## Environment Variables

Required in `.env` or environment:

```
Google-Custom-Search-JSON-API-KEY=AIza...
Google-Custom-Search-CX=327...
OPENROUTER_API_KEY=sk-or-...
```

Alternative key names also supported:
- `GOOGLE_CUSTOM_SEARCH_API_KEY`
- `GOOGLE_CUSTOM_SEARCH_CX`
- `OPENROUTER-API-KEY`

```

google-image-search | SkillHub