Tori.fi Ads Scraper avatar

Tori.fi Ads Scraper

Pricing

from $1.48 / 1,000 results

Go to Apify Store
Tori.fi Ads Scraper

Tori.fi Ads Scraper

Get structured data for public ads in Tori.fi search results, including IDs, titles, locations, seller types, trade labels, publication dates, images, and listing URLs. Search with keywords or use Tori.fi URLs to preserve filters; duplicate ads are removed across pages and searches.

Pricing

from $1.48 / 1,000 results

Rating

0.0

(0)

Developer

Axiom Works

Axiom Works

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Returns: one row per Tori.fi ad with id, title, price, currency, location, postedAt, images and sourceUrl. Input: {"searchQueries": ["polkupyora"], "minPrice": 50, "maxPrice": 150, "maxItems": 30} Best for: price monitoring of second-hand goods, reseller sourcing lists, local market research.

{
"id": "48437849",
"title": "Miesten hybrid",
"price": 200,
"currency": "EUR",
"location": "Kaleva, Tampere",
"sourceUrl": "https://www.tori.fi/recommerce/forsale/item/48437849"
}

What does Tori.fi Ads Scraper do?

Tori.fi Ads Scraper collects public classified advertisements from Tori.fi search results. Give it Finnish search keywords or a Tori.fi search URL, and it returns one structured record per advertisement. Each record has a stable ad ID and a link to its public listing. The Actor reads the public search page, including the page's embedded search data and structured data. No login is required.

The Actor follows Tori.fi search pagination, up to the site's first 50 pages for each input search. It fetches pages sequentially at a modest rate. It stops as soon as maxItems valid records have been emitted. The number of results depends on the public ads visible when the run starts, the query, filters, and the site's paging limit.

This is an independent tool. It is not affiliated with Tori.fi. The fields reflect the public search response, so they may differ from a listing's later edited detail page. If you need full descriptions or seller contact details, those are outside this Actor's output.

What data can you get?

The dataset contains one row for each unique public ad. Empty optional values are represented by null, and an ad with no images has an empty array. Title, location, ID, and source URL are required for a record to be emitted.

FieldMeaning
idStable Tori.fi advertisement ID.
titleHeading shown in search results.
priceNumeric asking price when present.
currencyCurrency code attached to the price.
locationPlace label shown with the ad.
sellerTypeprivate or business when the search flags identify it.
tradeTypeThe site's sale or trade label, such as Myydään.
latitudeLatitude supplied in search data; null when the ad has no map position.
longitudeLongitude supplied in search data.
postedAtPublication time converted to an ISO date string.
imagesPublic image URLs included with the search result.
conditionProduct condition from the page's structured data.
organisationNameBusiness name on retailer ads; null for private sellers.
brandBrand set on the ad, when the seller provided one.
attributesExtra attributes from the ad, keyed by attribute id with a list of values, or null.
categoryOptional coarse classification from TypeSafe AI.
sourceUrlCanonical public listing URL.

The search data supplies the ID, heading, price, location, seller flag, trade type, coordinates, timestamp, image URLs, and canonical URL. The page's JSON-LD structured data supplies condition when the matching ad appears there. When either source does not include an optional value, the record keeps null rather than guessing it. The images array contains URLs; the Actor does not download or store the image files.

If TYPESAFE_API_KEY is configured for the run, TypeSafe AI's Jev model classifies the title into a broad category: electronics, vehicles and parts, home and furniture, clothing and fashion, sports and leisure, or other. This enrichment uses a third-party AI processor. It sees the ad title for classification. A classification can be absent if the processor is unavailable or the run reaches its AI call limit. The source fields remain useful without the enrichment.

Posting-date filters support repeat market samples without changing the output format. Set postedAfter to a UTC calendar date such as 2026-10-01, and optionally set postedBefore to the last day to include. Both bounds include their named day. Empty strings disable the bounds. Ads without a timestamp are excluded when a date bound is active. Tori's timestamp can reflect a listing refresh; it is not a guarantee of first publication. Date filtering checks each returned ad and follows normal pagination, rather than assuming promoted results are in strict chronological order.

Set sellerType to private for household listings or business for ads carrying the site's retailer flag. The default all preserves the existing results. A filtered run only counts matching records toward the shared maxItems limit, and may fetch more search pages to find enough matches. Unknown seller flags are excluded from a specific seller selection. Combine these controls with the existing price bounds or URL filters for a narrower sample.

How to use

Enter at least one keyword in searchQueries, or provide one or more public Tori.fi search pages in startUrls. The two methods can be used together. Keywords are appropriate for a broad search. A search URL is useful when you have already chosen filters on Tori.fi and want the Actor to retain those URL parameters.

Set maxItems to the maximum number of unique ads to return across all inputs. The Actor considers the inputs in order: search URLs first, then keyword searches. For each input it walks pages in ascending page order. It skips any ad ID already emitted earlier in the same run. If fewer matching public ads exist, the run returns fewer records. A nonsense term yields an empty dataset with a warning.

sort controls keyword searches when the URL has no explicit sort parameter. The choices are relevance, newest publication, lowest price, and highest price. A supplied search URL can carry its own sort and other site filters. If a URL already contains sort, the Actor leaves it intact. Page numbers in a supplied URL establish where that input begins; subsequent pages increment from there.

Direct access is used by default. If public Tori.fi pages block a run, enable Apify Proxy using proxyConfiguration. The Actor retries block responses and rate limits with backoff and a fresh proxy session for each attempt. It never solves a CAPTCHA. A target that cannot obtain a usable public response is skipped with a warning; other targets continue. If no ads are returned, the successful run status suggests broader keywords, fewer price filters, a current search URL, or proxy settings. Missing targets or malformed inputs still fail validation.

The search pages are requested one at a time, at roughly one request per second. This pace helps avoid burdening the site. It also means a large result limit can take longer than a small one. The prefilled run collects at most 30 ads.

Input

InputTypeWhat to provide
searchQueriesArray of stringsFinnish keywords such as polkupyora; use this or startUrls.
startUrlsArray of URL objectsPublic Tori.fi search URLs, including any selected filters.
sortEnumRELEVANCE, PUBLISHED_DESC, PRICE_ASC, or PRICE_DESC; default PUBLISHED_DESC.
minPriceIntegerOnly ads priced at or above this amount in EUR. Ads without a price are excluded when set. Optional.
maxPriceIntegerOnly ads priced at or below this amount in EUR. Optional.
postedAfterStringOptional inclusive lower UTC date, YYYY-MM-DD; empty by default.
postedBeforeStringOptional inclusive upper UTC date, YYYY-MM-DD; empty by default.
sellerTypeEnumall (default), private, or business, based on source flags.
maxItemsIntegerMaximum unique ads, from 1 to 10000; default 50.
proxyConfigurationObjectOptional Apify Proxy settings; direct access by default.
maxJevCallsIntegerMaximum enrichment and fallback judgments, from 0 to 500; default 500.

Here is a keyword run with a strict result limit:

{
"searchQueries": ["polkupyora"],
"sort": "PUBLISHED_DESC",
"maxItems": 30,
"sellerType": "private",
"postedAfter": "2026-10-01"
}

Here is a search URL run. The URL can include Tori.fi filters selected in a browser:

{
"startUrls": [
{"url": "https://www.tori.fi/recommerce/forsale/search?q=iphone"}
],
"maxItems": 60
}

A URL must point to the public /recommerce/forsale/search route on www.tori.fi or tori.fi. Other target sites and listing detail URLs are outside this Actor's input scope. Search terms are sent as query parameters with proper URL encoding. A start URL is preserved when it advances to later pages, apart from its page value. Inputs that contain neither a usable keyword nor a search URL fail promptly with a clear message.

For an optional proxy run, set proxyConfiguration.useApifyProxy to true and, if needed, specify the supported Apify proxy group or country fields. The Actor asks Apify for a proxy URL on each retry, so blocked requests can use a fresh session. A normal direct run does not require a proxy configuration.

Output

The following real item came from a local sofa search using both date bounds and the private-seller filter. Listings may change after collection.

{
"id": "48459265",
"title": "Harmaa sohva",
"price": 150,
"currency": "EUR",
"location": "Sipoo, Sipoo",
"sellerType": "private",
"tradeType": "Myydään",
"latitude": 60.35936,
"longitude": 25.27203,
"postedAt": "2026-10-13T12:43:40.000Z",
"images": [
"https://img.tori.net/dynamic/default/item/48459265/16a153ce-807d-41f8-b80a-a6643474afb9",
"https://img.tori.net/dynamic/default/item/48459265/6d03e75b-25eb-49ea-8226-dfbee596109f"
],
"condition": "UsedCondition",
"brand": "IKEA",
"attributes": {
"brand": [
"IKEA"
]
},
"category": null,
"sourceUrl": "https://www.tori.fi/recommerce/forsale/item/48459265"
}

How much does it cost?

The Actor is charged per result. Each emitted ad counts as a result. An enriched-result event is recorded only when the optional AI category was actually produced. Setting a smaller maxItems bounds the number of emitted results. Check the Actor's Pricing tab for current event terms and rates; the tab is the source of truth as pricing can change.

A run that finds no ads emits no result records. Retried page requests do not themselves create extra output records. The Actor deduplicates ad IDs before pushing data, so an ad repeated on a later search page is still returned only once. It stops before pushing an item beyond maxItems.

Use with AI agents (MCP)

Apify's MCP server can expose this Actor as a tool to an AI agent. Configure the server URL with this Store path so the agent can discover the input schema and start a run:

https://mcp.apify.com/?tools=axiomworks/tori-fi-ads-scraper

An agent should supply either searchQueries or startUrls and an appropriate maxItems. The output dataset gives it stable IDs and source URLs, allowing it to refer back to the public ads it discusses. Examples of grounded requests an agent can make are:

Find up to 20 public Tori.fi bicycle ads for polkupyora and compare their asking prices and locations.

Collect up to 30 public Tori.fi iPhone listings from this search URL and return their titles, prices, and listing links.

Show which ads in a query have coordinates and which have image URLs, without filling missing fields from guesses.

Integrations and API

Python example using the Apify client:

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("axiomworks/tori-fi-ads-scraper").call(
run_input={"searchQueries": ["polkupyora"], "maxItems": 20}
)
items = list(client.dataset(run["defaultDatasetId"]).iterate_items())
for item in items:
print(item["id"], item["title"], item["sourceUrl"])

JavaScript example using the Apify client:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/tori-fi-ads-scraper').call({
searchQueries: ['polkupyora'],
maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => process.stdout.write(`${item.id} ${item.title}\n`));

A cURL call can start a run with JSON input. Replace the token placeholder in your own environment; do not put credentials in a public script or repository:

curl -X POST \
'https://api.apify.com/v2/acts/axiomworks~tori-fi-ads-scraper/runs' \
-H 'Authorization: Bearer YOUR_APIFY_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"searchQueries":["polkupyora"],"maxItems":20}'

FAQ

Can I use several keywords? Yes. Put several strings in searchQueries. The Actor processes them in order and removes duplicate ad IDs within the run. maxItems applies to the combined output, so the first search can consume the entire limit if it contains enough ads.

Can I search a category or price range? Yes. Select filters on a public Tori.fi search page and pass the resulting search URL in startUrls. The Actor retains the URL's query parameters while paging. It does not reinterpret the site's category IDs or price filters.

Why are some optional fields null? A public search result may omit coordinates, price, seller flags, or a structured condition. The Actor preserves missing values as null. It does not infer exact location, currency, seller type, or condition from unrelated words.

Why is the AI category null? The run may have no TypeSafe AI key, reach maxJevCalls, or receive an error from the processor. In these cases, the Actor continues with the source fields and does not record an enriched result. Classification is limited to broad product categories.

Can the Actor fetch more than 50 search pages? It follows the public search paging metadata with a maximum of 50 pages per input. Narrow filters or several search URLs can help collect a targeted sample. The Actor never invents additional pages beyond the site's reported range.

Does it visit detail pages? No. It reads public search pages and their embedded data. sourceUrl points to the detail page for a person or another workflow to inspect, but this Actor does not retrieve descriptions or seller contact information from that page.

What happens with an invalid URL or term? Unsupported URLs fail validation quickly. A valid search with no results finishes with zero dataset items and a warning. A blocked page is retried a few times with backoff, then the target is skipped. If all targets are unavailable, the run succeeds with zero items and advice to change the search or connection.

Public listing data can be subject to applicable law, site terms, and rights held by sellers or the platform. Check the rules relevant to your use, especially if you intend to republish data or retain it over time. This Actor reads public search pages, uses a modest request rate, and does not access account-only content. It does not solve CAPTCHAs or collect seller contact details. You remain responsible for how you use and store the output.

Feedback

If a field stops appearing, a page begins returning a block, or a search filter behaves unexpectedly, report the search input, run ID, and a short description of the observed result through the Actor's Apify feedback channel. Avoid posting credentials or private data. A reproducible public URL and the affected field help distinguish a site layout change from a query with no current advertisements.