Integrate the Flickr API into an application — searching and fetching photos, building photo/image URLs, OAuth authentication, consuming Flickr feeds, or calling any flickr.* REST method. Use this skill whenever the user wants to add Flickr to their app or backend, pull in Flickr photos, work with live.staticflickr.com image URLs, set up Flickr OAuth, or consume Flickr RSS/Atom/JSON feeds — even if they just say "Flickr" and "get some images." Covers any language (JS/TS, Python, etc.).
Flickr is a photo-hosting service with a large, well-documented REST API. This skill helps you wire the Flickr API into a real application: pick the right auth, call methods correctly, parse responses, and build image URLs.
The single most common mistake is overcomplicating auth. Public photo browsing needs nothing but an API key. Reach for OAuth only when the app touches private content or writes data. Decide that first (below), then build.
The developer must supply their own Flickr API key (free, from https://www.flickr.com/services/apps/create/). Read it from the environment, never from source:
export FLICKR_API_KEY="your-key"
export FLICKR_API_SECRET="your-secret" # only needed for OAuth (write/private access)
If the user pastes a key/secret into the chat, put it in their .env (and ensure .env is gitignored) — don't write it into the skill, a committed file, or example code. The API secret is only needed for OAuth request signing; pure public read calls use just the key.
Does the app only read PUBLIC data (search, public photos, public user info, feeds)?
└── Yes → API key only. No OAuth, no signing. This is most apps. Go to Step 2.
└── No (private photos, "me", uploads, faves, comments, edits, deletes)
└── OAuth 1.0a required (HMAC-SHA1 signed requests).
Read references/oauth.md — it's fiddly; follow it exactly,
or use a maintained OAuth1 library for your language.
Prefer an existing OAuth1 library (e.g. requests-oauthlib in Python, oauth-1.0a / passport-flickr in Node) over hand-rolling signatures. Hand-rolled HMAC-SHA1 base-string construction is the #1 source of signature invalid errors.
All API methods go through one endpoint via GET (or POST for writes):
https://api.flickr.com/services/rest/
Every request needs method and api_key. For app integration, always request JSON — the default is XML, which you don't want to parse in code:
https://api.flickr.com/services/rest/
?method=flickr.photos.search
&api_key=FLICKR_API_KEY
&text=golden+retriever
&per_page=20
&format=json
&nojsoncallback=1
format=json → JSON instead of the default XML (format=rest).nojsoncallback=1 → always include this. Without it Flickr wraps the body in jsonFlickrApi(...) (JSONP), which is not valid JSON and will break JSON.parse / json.loads. Only omit it if you genuinely want a JSONP callback in a browser <script> tag.JavaScript / TypeScript (fetch):
const params = new URLSearchParams({
method: "flickr.photos.search",
api_key: process.env.FLICKR_API_KEY,
text: "golden retriever",
per_page: "20",
format: "json",
nojsoncallback: "1",
});
const res = await fetch(`https://api.flickr.com/services/rest/?${params}`);
const data = await res.json();
if (data.stat !== "ok") throw new Error(`${data.code}: ${data.message}`);
const photos = data.photos.photo; // array of { id, owner, secret, server, ... }
Python (requests):
import os, requests
resp = requests.get("https://api.flickr.com/services/rest/", params={
"method": "flickr.photos.search",
"api_key": os.environ["FLICKR_API_KEY"],
"text": "golden retriever",
"per_page": 20,
"format": "json",
"nojsoncallback": 1,
})
data = resp.json()
if data["stat"] != "ok":
raise RuntimeError(f'{data["code"]}: {data["message"]}')
photos = data["photos"]["photo"]
Success:
{ "stat": "ok", "photos": { "page": 1, "pages": 50, "perpage": 20, "total": 1000,
"photo": [ { "id": "54321", "owner": "12037949754@N01", "secret": "abc123",
"server": "65535", "farm": 66, "title": "Buddy", "ispublic": 1 } ] } }
Failure (note: HTTP status is still 200 — you must check stat):
{ "stat": "fail", "code": 100, "message": "Invalid API Key" }
Always branch on data.stat === "ok" before reading the payload. See references/methods.md for the full error-code list and per-method notes.
A search result gives you server, id, and secret — not a URL. Build the image URL yourself:
https://live.staticflickr.com/{server}/{id}_{secret}_{size}.jpg
const url = (p, size = "w") =>
`https://live.staticflickr.com/${p.server}/${p.id}_${p.secret}_${size}.jpg`;
// medium 500px has NO suffix: ${p.server}/${p.id}_${p.secret}.jpg
Common sizes: w (400), z (640), c (800), b (1024). Medium 500px omits the suffix. Sizes b and above can be restricted by the owner. Two shortcuts that avoid guessing:
extras=url_w,url_z,url_c,url_l to flickr.photos.search and Flickr returns ready-made URLs (url_w, url_c, …) plus their dimensions directly in each photo record. This is the cleanest approach — use it instead of string-building when you can.flickr.photos.getSizes to get every available size with exact URLs.Full size table, original-photo URLs, web-page URLs, and flic.kr short URLs are in references/photo-urls.md.
List methods return page, pages, total, perpage. Page with per_page (max 500) and page. Flickr caps any search at the first 4,000 results regardless of total — for larger sweeps, narrow by date ranges (min_upload_date/max_upload_date) and page within each window rather than paging past result 4,000.
Flickr's standard non-commercial limit is 3,600 requests per hour per API key (confirm current terms for your key). Build for it: cache responses, request only the extras you need, use a sane per_page, and back off on code 105 (service unavailable) / HTTP 429. Commercial use requires applying for a commercial key.
For simple "show recent public photos by tag/user" widgets, you often don't need the API at all. Flickr publishes pre-baked feeds (RSS/Atom/JSON) with no API key:
https://www.flickr.com/services/feeds/photos_public.gne?tags=sunset&format=json&nojsoncallback=1
If the user just wants a lightweight public photo stream, suggest a feed first — it's simpler and unauthenticated. Full feed catalog, parameters, and formats in references/feeds.md.
Read the one you need; don't load them all:
references/methods.md — Full catalog of all flickr.* methods by namespace, signatures + key params for the most-used methods (search, getInfo, getSizes, getRecent, people/photosets/galleries), the extras field values, and the complete error-code table. Read when choosing a method or debugging a method-specific error.references/oauth.md — Complete OAuth 1.0a flow (request token → authorize → access token), signature base-string and signing-key construction, permission levels, and library recommendations. Read whenever the app needs write access or private data.references/photo-urls.md — Every image size suffix with dimensions, original-photo URLs, web-page URLs, short URLs, buddyicons. Read when building or debugging image URLs.references/feeds.md — All feed types, endpoints, parameters, and the full format list. Read when using feeds instead of the API.Authoritative source if anything here is stale: https://www.flickr.com/services/api/
skillbazaar install flickr-skill --agent claudeSign in (free) to install skills with the CLI.
Author
@jason