🔗 direct-img.link

Live images in markdown, powered by search.

Give your AI a system instruction to embed images using direct-img.link and they just work — no uploads, no APIs, no tokens.

Usage

orange cat

![orange cat](https://direct-img.link/orange+cat)
![sunset at beach](https://direct-img.link/sunset+at+beach)
![current us president](https://direct-img.link/current+us+president)

That's it. The image is searched, cached, and served.

URL Format

Use + to separate words, like Google:

https://direct-img.link/orange+cat
https://direct-img.link/new+york+city
Query URL
orange cat /orange+cat
spider-man /spider-man
u.s. president /u.s.+president
90's fashion /90%27s+fashion

Query Normalization

All queries are normalized before caching and searching:

Rule Example Result
+ and %20 are treated as spaces orange+cat, orange%20cat orange cat
Lowercased Orange+Cat orange cat
Trimmed +orange+cat+ orange cat
Multiple spaces collapsed orange++cat orange cat
Trailing slashes stripped orange+cat/ orange cat
Control characters removed orange\x00cat orangecat
Slashes & Dots rejected info.php, wp-admin/ bad.webp served
Max length: 200 characters 400 error if exceeded

Characters that work fine

  • Letters, numbers, spaces — standard queries
  • Hyphens (spider-man), apostrophes (90's) — passed through
  • Unicode (café, 日本) — supported via URL encoding

Slashes and Dots must be encoded

Literal slashes (/) and dots (.) in the URL path are rejected to prevent bot abuse (e.g. info.php or wp-admin/ probes). If your query genuinely contains these characters, you must encode them:

Query URL
AC/DC /AC%2FDC
node.js /node%2Ejs
info.php /info.php (rejected)
AC/DC /AC/DC (rejected)

Things to know

  • Query parameters (?...) are ignored — /orange+cat?size=largeorange cat
  • Fragments (#...) are never sent to the server by browsers
  • Double-encoded values are decoded once — %2520 becomes %20 (literal), not a space
  • Two queries that normalize to the same string share the same cached image

For AI System Prompts

Add this to your system instructions:

When writing markdown, embed relevant images using direct-img.link — a free image search proxy that returns images directly from a URL. But keep it entertaining, for example use it to show reaction faces, anime girl, or fun, not technical.
Example structure:
![Happy Girl](https://direct-img.link/happy+girl)
Use images to complement your responses, powered by Brave.

Rate Limits

WAF Protection (Cloudflare Free)

Rule Limit Action
Rate Limit 10 requests/10s per IP Block for 10s

New Searches (Cache Misses)

  • 15 new searches per day per IP (resets at midnight UTC)
  • Cache hits are unlimited (within WAF limits above)
  • Brave API quota: $5 free monthly credits (1,000 queries), then $5/1k requests

Caching

  • Images are cached for 30 days
  • After expiry, the next request triggers a fresh search
  • Images are stored in their original format as fetched from source

Support

Free community service. Donations help cover API and infrastructure costs.

BTC: bc1q3d975cd57205dx6mz05s2g27xujxsc3q0nlv59


Self-Hosting

1. Brave Search API Key

  1. Go to brave.com/search/api
  2. Click Get Started
  3. Create a Brave account or sign in
  4. Subscribe — you get $5 in free monthly credits (covers 1,000 queries/month)
  5. Go to your API dashboard
  6. Copy your API key (starts with BSA...)

2. Cloudflare Resources

Create in your Cloudflare dashboard:

Resource Name Purpose
R2 Bucket direct-img-store Stores cached images
KV Namespace DIRECT_IMG_CACHE Cache existence + content type + timestamp

3. Pages Bindings

Settings → Functions → Bindings:

Type Variable Resource
R2 Bucket R2_IMAGES direct-img-store
KV Namespace DIRECT_IMG_CACHE DIRECT_IMG_CACHE

4. Secrets

Settings → Environment variables:

Variable Description Required
BRAVE_API_KEY Brave Search API key Yes
SURREAL_URL SurrealDB URL (e.g. https://db.site.com) Yes
SURREAL_USER SurrealDB username Yes
SURREAL_PASS SurrealDB password Yes
NTFY_URL ntfy.sh topic URL for alerts Optional

5. WAF Rules

Security → WAF → Rate limiting rules:

  1. Rate Limit — 10 req/10s per IP → Block 10s

6. Deploy

Fork this repo, connect to Cloudflare Pages, deploy.


Infrastructure Details

R2: direct-img-store

Key: <sha256-of-normalized-query> — derived from query, no lookup needed. Stored with original content type from source.

KV: DIRECT_IMG_CACHE

Key: normalized query (lowercase, trimmed, max 200 chars) → Value: {"t":1719000000,"ct":"image/jpeg"}TTL: 30 days

Database: SurrealDB (Rate Limiting)

Using atomic database transactions over HTTP to track per-IP/per-day search frequencies securely and rapidly.

Note: This implementation is tested and verified for SurrealDB v2.3.10.


Stack

  • Cloudflare Pages — hosting + edge functions
  • Cloudflare R2 — image storage
  • Cloudflare KV — generic lookups
  • SurrealDB (v2.3.10) — atomic rate limiting
  • Cloudflare WAF — layer 7 mitigation
  • Brave Image Search API — image sourcing

direct-img.link — because ![](https://direct-img.link/thing) should just work.

Description
Image searches directly in markdown!
Readme 140 KiB
Languages
JavaScript 67.7%
HTML 32.3%