# Behance Projects Scraper (`dami_studio/behance-projects-scraper`) Actor

Search Behance and get one row per project: title, link, appreciations, views, comments, the creator and their profile, the creative fields it is filed under, its tags and its cover image. Up to 20 search terms a run. No account, no API key, no browser.

- **URL**: https://apify.com/dami\_studio/behance-projects-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Social media, Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.70 / 1,000 project scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Behance Projects Scraper

Search Behance and get the matching projects back as a table: title, link, appreciations, views, comments, the creator, the creative fields it is filed under, its tags and its cover image. No account, no API key, no browser.

- Up to 20 search terms in one run, one row per project, deduplicated across the terms.
- Filter by creative field, by how recently the work was published, and sort by appreciations, views, comments or date.
- Behance search is fuzzy. Projects that come back carrying none of your words are dropped before they are written, and you are not charged for them.
- Empty input returns a labelled sample row, free, so you can see the shape before spending anything.

### Price

**$3.70 per 1,000 projects**, plus a **$0.0006 start fee per run**.

This is a flat rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.

| Projects | Total cost |
|---|---|
| 100 | $0.3706 |
| 500 | $1.8506 |
| 1,000 | $3.7006 |
| 5,000 | $18.5006 |

One run returns at most 5,000 projects, and Behance itself stops any single search at 1,000, so the totals above are per run, and a bigger pull means more search terms or more runs.

#### What is actually charged

- **One `project-scraped` event per project row written to the dataset.** Nothing else is metered per row.
- **Free:** the sample row an empty run returns, and every diagnostic row: a blocked target, a dead URL, a search that matched nothing. Those rows all carry `"charged": false`.
- Projects Behance returned that carry none of your search words are dropped before they reach the dataset, so an off-topic match never costs you anything.
- A project matching two of your terms is written once and charged once.
- A run that finds nothing costs the start fee and nothing more.
- Rows never leave the dataset without a charge, and are never charged without a row.

### Input

```json
{
  "searchTerms": [
    "brand identity",
    "packaging design"
  ],
  "maxItems": 100,
  "sortBy": "appreciations",
  "publishedWithin": "month",
  "creativeField": "Branding"
}
```

| Field | What it does |
|---|---|
| `searchTerms` | What to search Behance for, one term per line. Up to 20 per run. The row budget is split evenly between them. |
| `maxItems` | Total rows across all terms. Default 100, ceiling 5,000. Keep it small while you are trying things out. |
| `sortBy` | Recommended, Curated by Behance, Most appreciated, Most viewed, Most commented, or Most recent. These are Behance's own six orderings. |
| `publishedWithin` | All time, Today, Past week or Past month. These four windows are the only ones Behance honours. |
| `creativeField` | Optional. One of Behance's 110 creative fields, the same list its site filter offers. Blank searches every field. |
| `proxyUrls` | Leave empty. Fill it in only if you want traffic to leave through proxy servers you already pay for, as `http://user:pass@host:port`. |

Run it with **empty input** and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.

### Output

One row per project. A real row from a real run:

```json
{
  "ok": true,
  "charged": true,
  "recordType": "project",
  "query": "coffee shop branding",
  "title": "COFFEEWORKSCO",
  "url": "https://www.behance.net/gallery/202298481/COFFEEWORKSCO",
  "appreciations": 137,
  "views": 2251,
  "comments": 70,
  "creatorName": "cem kutlu",
  "creatorUsername": "cmkutlu",
  "creatorUrl": "https://www.behance.net/cmkutlu",
  "creatorLocation": "Turkey",
  "collaborators": "Arda Kaya",
  "creativeFields": "Animation, Graphic Design, Illustration",
  "tags": "coffee shop, Coffee, branding, rebranding, brand identity, logo animation, logo, visual identity, Rhino, Logotype",
  "publishedAt": "2024-07-02T11:17:16.000Z",
  "coverImage": "https://mir-s3-cdn-cf.behance.net/projects/max_808/951c5b202298481.Y3JvcCw4MDgsNjMyLDAsMA.png",
  "slug": "COFFEEWORKSCO",
  "projectId": "202298481",
  "scrapedAt": "2026-09-20T09:54:20.229Z"
}
```

#### Field notes

- `query`: the term that found this project. With several terms you can tell which one hit.
- `appreciations`: Behance's like count, read at the moment of the run. It keeps moving.
- `views`: the project's view count at read time, same caveat.
- `comments`: the comment count at read time. The comments themselves are not returned.
- `creatorName`: the display name of the first owner. A project with several owners puts the rest in `collaborators`.
- `creatorLocation`: whatever the creator typed on their own public profile. Sometimes a city and country, sometimes just a country, sometimes nothing.
- `creativeFields`: the categories Behance files the project under, comma separated. This is the same list the `creativeField` input filters on.
- `tags`: the creator's own tags, comma separated, in the order they set them. Capitalisation is theirs.
- `publishedAt`: when the project was published, as ISO 8601 in UTC.
- `coverImage`: a direct link to the project's cover image at up to 808 pixels wide. The image is not downloaded.
- `projectId`: Behance's own id. Stable, and safe to use as a primary key when you re-run.

Every real row carries `"charged": true`. Sample rows carry `"_sample": true` and diagnostic rows carry `"_diagnostic": true` with an `errorCode` you can filter on, and neither is ever billed.

### How it works

- It asks Behance's own search service for exactly the fields that end up in a row, and nothing else. No page rendering, no headless browser, no login.
- Because it asks for a short list of fields rather than a whole page, one request carries hundreds of projects instead of a couple of dozen.
- Every project that comes back is checked against the words you typed (in the title, the tags, the creative fields and the creator's name) before it is written or charged.
- The pager pauses briefly between pages rather than hammering the search.

### What people use it for

- Finding the designers behind the work you like in a category, then looking them up yourself. The row gives you their profile link, not a contact detail.
- Watching what is doing well in a field right now: sort by appreciations, set "past week", run it on a schedule, and diff on `projectId`.
- Building a reference board without saving 200 screenshots. Every row has the cover image link and the tags the creator chose.
- Checking how a style or a term is actually used on Behance before you name a project that way. The `tags` column is the creators' own vocabulary, not a taxonomy someone imposed.
- Teaching and research: a flat, typed table of published work with dates, categories and engagement numbers loads straight into a spreadsheet.

### What this does not do

Worth knowing before you spend anything.

- **It does not return contact details.** No emails, no phone numbers, no social handles, no availability or rate information. None of that is requested and none of it is written. These are people's portfolios. The row gives you the public project and a link to the public profile, and that is where it stops.
- **It does not open the projects.** You get the cover image link and the numbers from the search result, not the images inside the project, not the project description and not the comments.
- **It does not download any images.** `coverImage` is a link. Fetching it is your side.
- **It does not scrape a creator's whole portfolio.** The input is a search, not a username.
- **It does not join anything to anything.** One row is one project, exactly as Behance published it.

### Reading the output

Every run writes three kinds of row, and they are easy to tell apart:

- **Real rows** carry `"charged": true` and `"recordType": "project"`. These are the rows you paid for, one billed event each.
- **The sample row** carries `"_sample": true` and `"charged": false`. There is exactly one, it only appears when the input had no search terms, and it is there so you can look at the output shape before you spend anything.
- **Diagnostic rows** carry `"_diagnostic": true`, `"charged": false` and an `errorCode` you can switch on: `NO_RESULTS` when a term matched nothing (or matched only off-topic work), `NETWORK` when Behance could not be reached, `RATE_LIMITED` when it throttled the run, `TIME_BUDGET` when the run ran out of time before reaching a term. Each carries a plain-English `error` and the `query` it belongs to.

If you only want the data, filter on `charged == true`. The count of those rows always equals the number of events you were billed for, so the dataset is its own invoice.

### Limitations

- Behance stops any single search at 1,000 projects, however deep you ask. Past that the search simply returns nothing more. If you need a wider net, use several terms rather than one.
- Search is fuzzy, and it is Behance's, not ours. A two-word term matches projects that hit either word, so "coffee shop branding" returns work tagged only "branding". Rows carrying none of your words are dropped and not charged, but the ones that keep a single word are kept.
- Appreciations, views and comment counts are a snapshot at read time and will differ from what the page shows a minute later.
- "Recommended" is Behance's own relevance ranking and its rules are not published. If you want a defensible ordering, sort by appreciations, views, comments or date instead.
- Only the four publishing windows Behance actually honours are offered: all time, today, past week, past month. There is no arbitrary date range.
- Private, draft and deleted projects are not visible to anyone logged out, so they are not returned.
- `creatorLocation` is free text the creator typed. It is not normalised, not geocoded, and is often blank.
- The comment count is returned; the comments are not. Neither is the project description or the images inside the project.
- A project can have several owners. The first is in the `creator*` fields and the rest are a comma-separated list in `collaborators`, which is a name list and nothing more.
- The hard ceiling is 5,000 rows and 20 search terms per run. For more than that, split the work across runs.

### Questions

**What happens if a term matches nothing?**

You get one uncharged diagnostic row for that term with `errorCode: "NO_RESULTS"`, and the run carries on to your other terms. You are never billed for a term that returned nothing. The same happens when Behance returns work that carries none of your words, and the row says how many were dropped.

**Why did I get fewer rows than I asked for?**

Three reasons, in order of likelihood. Behance stops any one search at 1,000 projects. Off-topic matches are dropped before they are written. And a project matching two of your terms is written once. The run log prints the kept and dropped counts for every term.

**Can I scrape one designer's portfolio?**

Not with this. The input is a search, not a username. Searching the designer's name will surface their work if their name is in their profile or their tags, but that is a search, not a portfolio export.

**Do I need a proxy?**

No. The run brings its own egress and the cost of it is already inside the price you see. The `proxyUrls` field exists only for callers who specifically want traffic to leave through servers they already own.

**Will the run fail if something goes wrong?**

No. A blocked, empty or broken response produces an uncharged diagnostic row explaining what happened, and the run still finishes as succeeded. A failed run would still bill you the start fee, which would mean paying to be told something went wrong.

**Can I run this on a schedule?**

Yes. Nothing is held between runs, so the same input is safe to repeat. Use `projectId` to work out which rows are new since last time.

**Does it return anything about the creator beyond their name?**

Their display name, their Behance username, the link to their public profile, and whatever location they typed on it. No email, no phone number, no other social account, no rate or availability information. None of that is requested.

# Actor input Schema

## `searchTerms` (type: `array`):

What to search Behance for, one term per line. Up to 20 terms per run. Each term is searched in turn until the run reaches the row limit below. Behance caps any single search at 1,000 projects, so add more terms rather than asking one term for more.

## `maxItems` (type: `integer`):

Total rows to return across all your terms. The budget is split evenly between them, so four terms and 200 rows gives you 50 of each. Default 100, hard ceiling 5,000. Keep it low while you are trying things out — you pay per row.

## `sortBy` (type: `string`):

The order Behance returns matches in. "Recommended" is its own relevance ranking and is what the site shows by default. "Most appreciated" and "Most viewed" bring the big numbers to the top; "Most recent" sorts by publish date.

## `publishedWithin` (type: `string`):

Limit results to work published recently. "All time" searches the whole archive. These four windows are the only ones Behance actually honours.

## `creativeField` (type: `string`):

Narrow the search to one of Behance's own creative fields, the same list its site filter uses. Leave it blank to search every field. Projects that come back without the field you picked are dropped and never charged.

## `proxyUrls` (type: `array`):

Leave this empty for a normal run. Fill it in only if you want the traffic to leave through proxy servers you already pay for, one URL per line, in the form http://user:pass@host:port.

## Actor input object example

```json
{
  "searchTerms": [
    "brand identity",
    "packaging design"
  ],
  "maxItems": 100,
  "sortBy": "recommended",
  "publishedWithin": "all"
}
```

# Actor output Schema

## `results` (type: `string`):

Every row in the default dataset: query, title, url, appreciations, views, comments, creatorName, creatorUsername, creatorUrl, creatorLocation, collaborators, creativeFields, tags, publishedAt, coverImage, slug, projectId. An empty, blocked or unmatched run returns a single uncharged row explaining what happened instead.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "brand identity",
        "packaging design"
    ],
    "maxItems": 100,
    "sortBy": "recommended",
    "publishedWithin": "all",
    "creativeField": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/behance-projects-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchTerms": [
        "brand identity",
        "packaging design",
    ],
    "maxItems": 100,
    "sortBy": "recommended",
    "publishedWithin": "all",
    "creativeField": "",
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/behance-projects-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "brand identity",
    "packaging design"
  ],
  "maxItems": 100,
  "sortBy": "recommended",
  "publishedWithin": "all",
  "creativeField": ""
}' |
apify call dami_studio/behance-projects-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/behance-projects-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/U6n8KkFHVDOlwUQYN/builds/ZFDTl2hOYM9IgVWca/openapi.json
