# Thingiverse Scraper (`maximedupre/thingiverse-scraper`) Actor

Scrape public Thingiverse 3D model data from search terms, search URLs, model URLs, or thing IDs. Export titles, creators, tags, images, likes, downloads, licenses, dates, and file metadata.

- **URL**: https://apify.com/maximedupre/thingiverse-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Developer tools, E-commerce, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.45 / 1,000 scraped models

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

### 🧩 Thingiverse scraper for 3D model data

Thingiverse Scraper collects public 3D model data from [Thingiverse](https://www.thingiverse.com/). Use it to scrape Thingiverse search results, enrich known model URLs, or look up specific thing IDs in one clean Apify dataset.

Start with a plain search term such as `phone stand`, paste a Thingiverse search URL, add a model URL such as `https://www.thingiverse.com/thing:2120591`, or enter the numeric thing ID directly. The Actor returns model titles, creators, tags, preview images, engagement metrics, licenses, dates, and file metadata when Thingiverse exposes those values.

For a quick first run, keep the prefilled `phone stand` target and leave **Maximum results** at `96`. Direct model URLs and thing IDs are processed once, while search targets use the result limit.

### ✅ What this Actor does

- Scrapes public Thingiverse model search results from plain search terms.
- Accepts Thingiverse search result URLs.
- Accepts direct Thingiverse model URLs.
- Accepts numeric thing IDs.
- Saves one dataset row per successful Thingiverse model.
- Adds search context with `searchQuery` and `searchPosition` when a row comes from a search target.
- Returns model identity, title, description, creator, tags, images, metrics, license, dates, and file metadata when available.
- Deduplicates models by stable Thingiverse ID during the run.
- Charges only for saved model rows.

This Actor focuses on public 3D model metadata. It does not scrape Thingiverse blog posts, private or unavailable models, creator profile pages as separate rows, comments as separate rows, or bulk-download and store 3D model files.

### 📦 Data you can export

Each output row represents one Thingiverse model. Fields include:

- `thingId` - stable Thingiverse model ID.
- `title` and `description` - model text when available.
- `creatorName` and `creatorUsername` - creator identity.
- `searchQuery` and `searchPosition` - discovery context for search results.
- `publishedAt` and `updatedAt` - model dates when Thingiverse exposes them.
- `license` - license name and URL when available.
- `categories` and `tags` - Thingiverse labels attached to the model.
- `likeCount`, `collectCount`, `commentCount`, `downloadCount`, `makeCount`, and `remixCount` - source-backed metrics when available.
- `imageUrls` - public preview and model image URLs.
- `files` - available file names, URLs, and file sizes when available.

Fields can be `null` or empty when Thingiverse does not expose a value for a model. The dataset does not include skipped-target rows, error rows, raw payloads, or hidden runtime diagnostics.

### 🚀 How to run it

1. Add one or more **Thingiverse targets**.
2. Use search terms, Thingiverse search URLs, model URLs, thing IDs, or a mix of them.
3. Set **Maximum results** for search targets.
4. Run the Actor.
5. Open the dataset or export the results.

Good first inputs:

```json
{
	"targets": ["phone stand"],
	"maxItems": 25
}
````

For known models:

```json
{
	"targets": [
		"https://www.thingiverse.com/thing:2120591",
		"2120591"
	],
	"maxItems": 25
}
```

For a source-native search URL:

```json
{
	"targets": [
		"https://www.thingiverse.com/search?q=raspberry%20pi%20case&page=1&type=things"
	],
	"maxItems": 50
}
```

### ⚙️ Input options

#### 🎯 Thingiverse targets

Add one target per line. Supported target types are:

- Plain search terms, such as `phone stand` or `raspberry pi case`.
- Thingiverse search URLs with a `q` search parameter.
- Thingiverse model URLs in the `https://www.thingiverse.com/thing:2120591` format.
- Numeric thing IDs, such as `2120591`.

Empty targets are ignored. Unsupported targets are handled through logs instead of fake dataset rows.

#### 🔢 Maximum results

`maxItems` controls how many model rows can be saved from search targets in one run. It does not multiply direct model URLs or thing IDs, because each direct target represents one model.

The default is `50`, the minimum is `1`, and the maximum is `1000`.

### 🧾 Output example

```json
{
	"thingId": "2120591",
	"title": "Phone Stand",
	"description": "A simple phone stand for desk use.",
	"creatorName": "GoAftens",
	"creatorUsername": "GoAftens",
	"searchQuery": "phone stand",
	"searchPosition": 1,
	"publishedAt": "2017-02-18T22:33:56.000Z",
	"updatedAt": "2017-02-18T22:33:56.000Z",
	"license": {
		"name": "Creative Commons - Attribution",
		"url": "https://creativecommons.org/licenses/by/4.0/"
	},
	"categories": [],
	"tags": ["desk", "dock", "iphone", "phone", "stand"],
	"likeCount": 37691,
	"collectCount": 40091,
	"commentCount": 145,
	"downloadCount": 410003,
	"makeCount": 226,
	"remixCount": 156,
	"imageUrls": [
		"https://cdn.thingiverse.com/assets/12/eb/52/8e/15/Phone_stand03.jpg"
	],
	"files": [
		{
			"name": "Phone_Stand03.STL",
			"downloadUrl": "https://cdn.thingiverse.com/assets/0c/60/ed/2e/5a/Phone_Stand03.STL",
			"sizeBytes": null
		}
	]
}
```

### 💳 Pricing

This Actor uses pay-per-event pricing. You are charged for each saved Thingiverse model row through the `scraped-model` event. Skipped targets, duplicate models, no-result searches, and internal diagnostics are not charged as model results.

The planned local pricing artifact is `$0.00445` per saved model.

### 🧭 Limits and caveats

- The Actor returns public metadata exposed by Thingiverse. It does not invent missing descriptions, dates, licenses, counts, categories, tags, or file sizes.
- File entries are metadata and source URLs. The Actor does not download, zip, host, or mirror model files for you.
- Search order follows the source result order returned for the target search.
- Direct model targets have `searchQuery` and `searchPosition` set to `null`.
- Unavailable, private, removed, invalid, or unsupported targets are reported in logs and are not emitted as dataset rows.

### ❓ FAQ

#### 🔎 Can I scrape both search results and direct model URLs in one run?

Yes. Add search terms, search URLs, model URLs, and numeric thing IDs to the same **Thingiverse targets** list. The Actor deduplicates models by `thingId`.

#### 🧱 Does this Actor download STL or 3MF files?

No. It returns file metadata and URLs when Thingiverse exposes them. It does not bulk-download, store, zip, or rehost 3D model files.

#### 🔐 Do I need a Thingiverse account?

No user-provided Thingiverse login, cookie, or source API key is required for the public model metadata workflow.

#### 📊 Can I export the data?

Yes. After the run, open the Apify dataset and export it as JSON, CSV, Excel, XML, RSS, or HTML. You can also use the Apify API, schedules, webhooks, and integrations.

### 📝 Changelog

- 0.0: Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~thingiverse-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Other actors

- [DeviantArt Scraper ↗](https://apify.com/maximedupre/deviantart-scraper) - Scrape public artwork, creator data, images, and contact snippets.
- [Unsplash Image Scraper ↗](https://apify.com/maximedupre/unsplash-image-scraper) - Collect public image search results for design and content research.
- [Pinterest Keyword Scraper ↗](https://apify.com/maximedupre/pinterest-keyword-scraper) - Collect Pinterest autocomplete ideas for SEO and content planning.
- [Artbreeder AI Image Creator ↗](https://apify.com/maximedupre/artbreeder-ai-image-creator) - Generate image URLs and metadata from Artbreeder prompts.
- [Craiyon AI Image Creator ↗](https://apify.com/maximedupre/craiyon-ai-image-creator) - Generate prompt-based images and export source or Apify download URLs.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

## `targets` (type: `array`):

One target per line. Use a search term, Thingiverse search URL, model URL, or thing ID.

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

Maximum number of model rows to collect from search targets. Direct model targets are processed once.

## Actor input object example

```json
{
  "targets": [
    "phone stand"
  ],
  "maxItems": 96
}
```

# Actor output Schema

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

Open the default dataset with scraped Thingiverse model rows.

# 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 = {
    "targets": [
        "phone stand"
    ],
    "maxItems": 96
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/thingiverse-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 = {
    "targets": ["phone stand"],
    "maxItems": 96,
}

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

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

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

```

## CLI example

```bash
echo '{
  "targets": [
    "phone stand"
  ],
  "maxItems": 96
}' |
apify call maximedupre/thingiverse-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=maximedupre/thingiverse-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Thingiverse Scraper",
        "description": "Scrape public Thingiverse 3D model data from search terms, search URLs, model URLs, or thing IDs. Export titles, creators, tags, images, likes, downloads, licenses, dates, and file metadata.",
        "version": "0.0",
        "x-build-id": "0TrbxZu5lGRTECOzK"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/maximedupre~thingiverse-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-maximedupre-thingiverse-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/maximedupre~thingiverse-scraper/runs": {
            "post": {
                "operationId": "runs-sync-maximedupre-thingiverse-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/maximedupre~thingiverse-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-maximedupre-thingiverse-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "targets",
                    "maxItems"
                ],
                "properties": {
                    "targets": {
                        "title": "Thingiverse targets",
                        "minItems": 1,
                        "maxItems": 100,
                        "type": "array",
                        "description": "One target per line. Use a search term, Thingiverse search URL, model URL, or thing ID.",
                        "items": {
                            "type": "string",
                            "minLength": 1
                        }
                    },
                    "maxItems": {
                        "title": "Maximum results",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of model rows to collect from search targets. Direct model targets are processed once.",
                        "default": 96
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
