Files
direct-img.link/README.md

5.9 KiB

🔗 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
KV Namespace DIRECT_IMG_RATE Per-IP daily search tracking

3. Pages Bindings

Settings → Functions → Bindings:

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

4. Secrets

Settings → Environment variables:

Variable Description Required
BRAVE_API_KEY Brave Search API key Yes
NTFY_URL ntfy.sh topic URL for traffic/error 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

KV: DIRECT_IMG_RATE

Each new search writes a unique key to avoid race conditions with concurrent requests:

Key: <ip>:<YYYY-MM-DD>:<timestamp>-<uuid>Value: "1"TTL: 25 hours

To check usage, list({ prefix: "<ip>:<YYYY-MM-DD>:" }) counts the keys. No read-modify-write, no race condition.


Stack

  • Cloudflare Pages — hosting + edge functions
  • Cloudflare R2 — image storage
  • Cloudflare KV — cache + rate limiting
  • Cloudflare WAF — rate limiting + DDoS protection
  • Brave Image Search API — image sourcing

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