Choosing a Behance Integration Method: API v2, oEmbed, or Scraping
Compare Behance API v2, oEmbed, and scraping for embedding portfolio projects. Covers rate limits, auth, image URL lifetimes, CSP impact, and provides ready‑to‑run curl/Playwright examples.
18 Jan 2026, 22:43 UTC

Decision and Constraints
You need to surface Behance projects in an external site or app. The three supported paths are:
- Official API v2 – REST endpoints with OAuth 2.0, structured JSON, search, pagination.
- oEmbed endpoint – Unauthenticated, returns ready‑made embed HTML/JSON for a single project or collection URL.
- Web scraping – Full DOM access but violates Behance ToS §3.2 and is brittle.
Key constraints that shape the choice:
- Rate limit: 150 requests/hour per IP (shared across all apps on that IP).
- Authentication: API v2 needs a registered key; private data requires OAuth user consent (token expires 180 days, no refresh).
- Data freshness: Image URLs are signed and expire in 24‑48 hours; search does not index full project descriptions.
- Maintenance burden: Scraping breaks on UI changes; oEmbed loads third‑party scripts that affect CSP.
Supported Options Compared
| Criterion | API v2 | oEmbed | Scraping |
|---|---|---|---|
| Authentication | API key + optional OAuth 2.0 (client_credentials for public, authorization_code for private) | None | None (but may need login cookies for private content) |
| Rate limit | 150 req/hr per IP (headers X-RateLimit-*) | No published limit; subject to generic web traffic limits | No protection; easy to get blocked |
| Data scope | Projects, users, collections, search (title, tags, fields, owner) | Single project/collection embed only | Everything rendered in browser (including private if authenticated) |
| Response format | JSON (paginated, cursor‑based, max 24 items/page) | JSON or HTML embed snippet | HTML/DOM – must parse yourself |
| Image handling | CDN URLs with multiple resolutions (404‑1200 px), signed, short‑lived | Embed JS loads images via Behance CDN | Direct img src attributes (may be lazy‑loaded) |
| CORS | GET allowed with API key in query; POST/OAuth need server proxy | Iframe embed bypasses CORS entirely | Same‑origin policy blocks browser scraping; server‑side only |
| ToS compliance | Fully supported | Supported | Violates §3.2 |
| Maintenance | Low – stable endpoints, but watch for deprecation (maintenance mode) | Very low – only URL format changes | High – UI changes, React rendering, infinite scroll |
Trade‑offs
API v2 – Full control, higher ops cost
Best when you need search, lists, or programmatic access to metadata (tags, fields, ownership). You must cache responses and refresh image URLs at least daily. A server‑side proxy protects client_secret and lets you pool a dedicated IP to avoid the shared 150 req/hr ceiling.
oEmbed – Zero‑code embed, limited data
Ideal for “show this project” widgets. The response includes a <script> that loads Behance’s embed JS and tracking pixels; audit your Content‑Security‑Policy if you run a strict CSP. No search, no pagination, no access to raw image URLs.
Scraping – Maximum fidelity, legal risk
Only consider if you need data the API explicitly excludes (e.g., private drafts you own). You’ll need a headless browser (Puppeteer/Playwright) to execute React, handle infinite scroll, and wait for lazy‑loaded images. Expect frequent breakage and no SLA.
Concrete Implementation & Validation
1. API v2 – Fetch a public project list
Run on any machine with curl (or your HTTP client). Replace YOUR_KEY with the key from developer.behance.net.
curl "https://api.behance.net/v2/projects?api_key=YOUR_KEY&page=1&per_page=12"
Check response headers for rate‑limit info:
curl -I "https://api.behance.net/v2/projects?api_key=YOUR_KEY&page=1"
# Look for X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
Validate image URL expiration: fetch the same project twice, 25 hours apart, and compare the images[0].sizes["400"] values. They should differ.
2. OAuth 2.0 – Access private projects (server‑side only)
- Register a redirect URI in the developer dashboard.
- Direct the user to
https://www.behance.net/oauth/authorize?client_id=YOUR_ID&redirect_uri=YOUR_REDIRECT&response_type=code&scope=projects. - Exchange the returned
codefor an access token (POST tohttps://api.behance.net/v2/oauth/tokenwithclient_id,client_secret,grant_type=authorization_code). - Use the token in the
Authorization: Bearer <token>header for subsequent calls.
Token expires in 180 days; there is no refresh token – you must repeat the flow.
3. oEmbed – Embed a single project
curl "https://www.behance.net/oembed?url=https://www.behance.net/gallery/12345678/Project-Name&format=json&maxwidth=800"
The JSON field html contains an <iframe> plus a <script>. Insert the html string directly into your page. Verify CSP by loading the page and checking the console for blocked script errors.
4. Scraping (not recommended) – Proof‑of‑concept with Playwright
const pw = require('playwright');
(async () => {
const browser = await pw.chromium.launch();
const page = await browser.newPage();
await page.goto('https://www.behance.net/gallery/12345678/Project-Name', {waitUntil: 'networkidle'});
// Scroll to trigger lazy images
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(2000);
const images = await page.$$eval('img[src*="behance.net"]', imgs => imgs.map(i => i.src));
console.log(images);
await browser.close();
})();
Run this on a server you control. Expect breakage when Behance updates its React components or adds new anti‑bot measures.
Limitations & Practical Checks
- API v2 – Search cannot query full project descriptions; only titles, tags, fields, owner names. Monitor developer.adobe.com/behance for deprecation notices (API is in maintenance mode).
- oEmbed – No programmatic access to metadata; embed script adds third‑party cookies and tracking. Test with
Content-Security-Policy: script-src 'self' https://www.behance.net;and adjust as needed. - Scraping – Violates ToS; no rate‑limit headers; image URLs may be behind signed CDN tokens that expire quickly.
Quick health check for any integration: after deployment, log the X-RateLimit-Remaining header (API) or the HTTP status of the oEmbed request. If you see 429 or a sudden drop in remaining quota, add a caching layer (Redis, in‑memory) keyed by project ID with a TTL of 12 hours.
Decision Checklist
- Need search or lists? → API v2.
- Only occasional single‑project embeds? → oEmbed.
- Must read private drafts you own and accept ToS risk? → Scraping (last resort).
- Can you run a server‑side proxy for OAuth and caching? → API v2 becomes low‑maintenance.
- Strict CSP environment? → Prefer API v2 + self‑hosted image proxy over oEmbed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.