Autoplius.lt Car Ads Extractor
Under maintenancePricing
Pay per usage
Autoplius.lt Car Ads Extractor
Under maintenanceExtracts publicly available used-car listings from Autoplius.lt. Paste a search URL from the site and every matching public ad comes back as structured data — price, year, mileage, VIN, photos and the full parameter table. Only data any visitor can see on the site is returned.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
steeriq
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
2
Monthly active users
11 days ago
Last modified
Categories
Share
What does Autoplius.lt Car Ads Extractor do?
This actor turns the used-car listings on Autoplius.lt — Lithuania's largest car marketplace — into structured data: price, year, mileage, engine, gearbox, VIN, photos and the full parameter table for every ad a search matches. Paste a search URL from the site, run the actor, and get a dataset back — no code required, though the same input works identically through the API for a scheduled or programmatic pipeline.
Everything it collects is what any visitor sees on Autoplius' own public pages. It signs in to nothing and reaches nothing behind a login, a paywall or a private seller area.
Built on Crawlee and the Apify SDK, it gets Apify's proxy rotation, scheduling, dataset export and monitoring for free — you don't manage a server, a proxy pool, or a Chromium install.
Why use this actor?
- Market research and pricing. Pull every ad for a make/model/year band to see what cars are actually asking and selling for right now, not last quarter.
- Lead generation for dealers. Watch a segment (e.g. diesel estates under €15k) for new listings without refreshing the site by hand.
- Fleet or inventory monitoring. Track your own listings' visibility, or a competitor's, over time.
- Data feeds. Cars, prices and specs as clean JSON/CSV for a downstream app, spreadsheet, or BI tool.
How to use Autoplius.lt Car Ads Extractor
- Open autoplius.lt and build the search you want using the site's own filters — make, model, price, year, equipment, seller type, damage status, colour, anything the site offers.
- Copy the resulting URL and paste it into Start URLs on the Input tab.
- Click Start. Leave the other fields on their defaults for a first run.
- When the run finishes, open the Output tab, or download the dataset as JSON, CSV, Excel or HTML from the Export button.
Several Start URLs are fine — their results are merged and de-duplicated, so two overlapping searches never produce the same ad twice.
{"startUrls": [{"url": "https://en.autoplius.lt/ads/used-cars?category_id=2&make_id[97]=&make_id_list=97",},],"scrapeDetails": true,"maxItems": 1000,}
Both autoplius.lt and en.autoplius.lt URLs work — a Lithuanian or Russian or Latvian search
URL is rewritten onto the English site before it's fetched, so field labels and values always
come back in English regardless of which language you searched in.
Single ad URLs work too
Start URLs don't have to be searches. Paste a link straight to one ad — copied off the site, or
out of another dataset — and the actor recognizes it and scrapes just that ad directly, skipping
the search/listing step entirely. Anything else in Start URLs is treated as a search and
paginated as usual. The two are told apart automatically, by whether the URL carries an ad id
(the -<digits>.html at the end), so a mix of search and single-ad URLs in the same run works
with nothing to configure.
The filter fields are a fallback
makes, priceFrom/priceTo, yearFrom/yearTo, mileageFrom/mileageTo,
powerFrom/powerTo, fuelType, bodyType and gearbox exist for callers building input
programmatically who don't have a URL to hand. They rebuild an Autoplius search from scratch and
reach only a subset of what the site's own search can express — anything else the site offers
(only cars in Lithuania, exclude a given country, equipment, colour, seller type, damage status)
is reachable only by pasting a URL.
They're used only when Start URLs is empty — set a Start URL and every filter field is silently ignored (the run log names each one it dropped, so nothing fails quietly). Two limits worth knowing if you rely on them: make names must match the built-in list exactly, and model IDs are site-internal numbers you still have to copy out of a URL — at which point pasting the whole URL is simpler.
Input
| Field | Type | Description |
|---|---|---|
startUrls | array | Primary input. One or more autoplius.lt search URLs. |
makes, yearFrom/To, priceFrom/To, mileageFrom/To, powerFrom/To, fuelType, bodyType, gearbox | — | Fallback filters, used only when startUrls is empty. |
scrapeDetails | boolean | Visit each ad's own page for the full parameter set, VIN, description and every photo. Off = results-page fields only, at a fraction of the requests. Default true. |
transport | string | auto (HTTP, capped browser fallback for blocked requests — recommended), http (cheapest, no fallback), or browser (renders every page in Chromium). Default auto. |
maxItems | integer | Stop after this many ads. Default 1000. |
maxConcurrency | integer | Parallel requests for the HTTP tier. Default 5. |
maxRequestRetries | integer | Retries before a blocked request is handed to the browser fallback (auto mode). Default 5. |
proxyConfiguration | object | Defaults to Apify's residential proxy pinned to Lithuania — see below. |
skipSeenAds | boolean | Advanced. Skip ads a previous run with this actor already pushed. Default false. |
seenAdsStoreName | string | Names the store skipSeenAds remembers ad ids in. Default AUTOPLIUS-SEEN-ADS. |
See the Input tab for the full schema, including the make list.
A Lithuania-pinned residential proxy is not optional. Autoplius sits behind Cloudflare and 403s most foreign and datacenter exit IPs — testing an unpinned proxy got blocked on every attempt, while an LT-pinned residential proxy got through. The default is already correct; changing it is what breaks runs.
Output
One dataset record per ad. Known parameters are mapped to typed fields, and every label/value
row from the ad's own parameter table is additionally kept verbatim in rawParameters — so a
label the site adds or renames shows up as a new key instead of silently vanishing.
{"id": "31732033","url": "https://en.autoplius.lt/ads/bmw-328-2-0-l-saloon-sedan-2012-petrol-31732033.html","title": "BMW 328","make": "BMW","model": "328","price": 25000,"currency": "EUR","year": 2012,"mileageKm": 282000,"fuelType": "Petrol","gearbox": "Automatic","bodyType": "Saloon / sedan","engineCapacityL": 2,"powerKw": 180,"vin": null,"co2Gkm": 149,"location": "Kėdainiai, Lithuania","imageUrls": ["https://autoplius-img.dgn.lt/ann_3_407330359/bmw-328-2-0-l-saloon-sedan-2012-petrol-0.jpg"],"isSold": false,"rawParameters": { "Climate control": "Climate control", "Advertisement ID": "A31732033" },"scrapedAt": "2026-09-03T18:40:34.746Z"}
You can download the dataset in JSON, CSV, Excel, HTML, XML or RSS from the Export button on the Output tab, or pull it through the Apify API for automation.
Data fields
| Field | Description |
|---|---|
id, url | Ad id and canonical URL. |
title, make, model | Listing title, split into make/model. |
price, currency | Asking price. |
year, firstRegistration | First-registration year and the raw date string. |
mileageKm | Odometer reading. |
fuelType, gearbox, bodyType | As shown on the ad. |
engineCapacityL, powerKw | Engine size and power. |
drivenWheels, doors, color, seats, wheelDiameter | (detail pages only) |
vin | (detail pages only) Null unless the seller's VIN passes a plausibility check — Autoplius masks most VINs behind a click-to-reveal the actor doesn't interact with. |
co2Gkm, euroStandard, technicalInspectionUntil, weightKg, registrationTaxEur | (detail pages only) |
location | Seller's stated location. |
description | (detail pages only) Free-text ad description. |
imageUrls | This ad's own photos — the related-ads carousel elsewhere on the page is deliberately excluded. |
isSold | Whether the ad is flagged sold/inactive. |
rawParameters | (detail pages only) Every label/value row from the ad, verbatim — the safety net for anything not mapped above. |
scrapedAt | ISO timestamp of extraction. |
Consistency with the sibling Autogidas actor
This actor has a sibling, the Autogidas.lt Car Ads Extractor, covering a second Lithuanian car marketplace. Every field the two sites both publish uses the same name and type in both actors' output, so a pipeline consuming either dataset can treat them interchangeably for the fields they share. A few fields deliberately differ, because the sites themselves differ:
vinhere isnullunless the value looks like a genuine, unmasked VIN. The sibling actor'svinPartialis always just the visible (usually masked) prefix text, unvalidated — a different kind of value, not the same field under two names.powerFrom/powerTo(input) exist here because Autoplius' search exposes a power filter; the sibling site doesn't, so it has no equivalent.- The sibling actor additionally reports
sellerName,cylinders,gears,firstRegistrationCountry,steeringSide,defectsand per-context fuel consumption, because Autogidas' parameter table publishes them and Autoplius' doesn't.
These field names and shapes are meant to stay stable — a schema change here should be considered alongside the sibling actor's, not made independently.
Run outcome
Alongside the dataset, every run writes a RUN-SUMMARY record to its default key-value store and
puts the same headline into the run's status message. It tells a downstream actor whether the
dataset it just received is the whole answer, without having to guess from the item count:
outcome | Run status | Means |
|---|---|---|
complete | SUCCEEDED | Every ad the search offered was extracted. |
partial | SUCCEEDED | Real data came back, but some pages never did — dataset incomplete. |
empty | SUCCEEDED | Every page loaded fine and the search matched no ads. |
blocked | FAILED | Nothing could be read at all — usually proxies or a JS challenge. |
{"outcome": "partial","adsPushed": 20,"adsExpected": 25,"adsMissing": 5,"failedListPages": 1,"failedDetailPages": 4,"skippedKnownAds": 0,"failedUrls": [{"url": "https://autoplius.lt/skelbimai/naudoti-automobiliai/audi-a6-12345678.html","label": "DETAIL","message": "Blocked (403)"}],"failedUrlsTruncated": false}
adsExpected is how many ads the search pages offered and the run committed to, so
adsMissing is the real shortfall. A failed DETAIL page costs one known ad; a failed LIST
page costs a whole page of ads the run never learned about, which is why the two are counted
separately. failedUrls is capped at 100 entries, with failedUrlsTruncated flagging the cut —
retry them by feeding them back in as startUrls.
Reading it from a calling actor:
const run = await client.actor('you/autoplius-scraper').call(input);const { value: summary } = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('RUN-SUMMARY');if (summary.outcome === 'partial') {console.warn(`Incomplete: ${summary.adsMissing} ad(s) missing`, summary.failedUrls);}
run.statusMessage carries the same headline as plain text if you only need a cheap check and
not the failed urls.
Pricing / cost estimation
This actor bills on Apify's standard pay-per-usage compute-unit model — there's no separate per-result charge. Two things drive cost, both under your control on the Input tab:
scrapeDetails. Results-page-only runs are cheap: one request per 20 ads. Full details cost one extra request per ad — turn it off if you only need price/year/mileage/location.transport. Left onauto(the default), almost every request is a plain HTTP fetch; Chromium is only launched for the small number Cloudflare actually blocks, and even then at capped concurrency. Forcingtransport="browser"prices every single request at browser rates.
A typical scrapeDetails: true, maxItems: 1000 run on the default 1024 MB should stay well under
the Apify Free plan's monthly compute-unit allowance — check the Runs tab for exact figures after
your first run, since actual cost depends on how many requests needed the browser fallback.
Tips for optimizing runs
- Slice large pulls instead of raising
maxItemspast ~5,500. One search caps out around 275 pages; past that the site re-serves the last page instead of an empty one. To cover more of the ~40k-ad catalogue, pass several Start URLs sliced by make, price band or year instead. - Turn
skipSeenAdson for a recurring/scheduled search. It remembers every ad id already pushed in a store that survives across runs, so a daily "what's new" run only pays for genuinely new listings. Tradeoff: an ad already seen is never revisited, so a price change or a sold flag on an old ad won't be picked up — run occasionally with it off for a full refresh. - Leave
transportonauto. It's never more expensive thanhttpwhen nothing gets blocked, and it recovers automatically when something does. - Don't lower
maxConcurrencyor raise it past ~10 without a reason — Cloudflare's challenge rate is sensitive to burstiness, and a blocked run costs more (retries, browser fallback) than a slightly slower one.
FAQ
Is this legal? The actor only reads pages any visitor can load without logging in. You're responsible for how you use the extracted data — check Autoplius' terms of service and applicable law (e.g. GDPR if a description or seller name ever includes personal data) for your use case.
Why is vin usually null? Autoplius masks most VINs behind a click-to-reveal control on
the ad page; the actor doesn't click it, so a masked value is deliberately reported as null
rather than the truncated placeholder text underneath it.
A run returned 0 ads. The run status tells you which of the two cases it was. A succeeded
run with 0 ads means every page loaded fine and the search genuinely matched nothing — widen the
filters, or open the start url in a browser to confirm. A failed run with 0 ads means no page
could be read: almost always a proxy problem, so confirm proxyConfiguration is still the
LT-pinned residential default (see above). If it's already correct and the site is failing a JS
challenge, set transport="browser" to render pages in a real browser, which clears it. A
succeeded run can still warn that some requests failed after retries — the dataset is then real
but incomplete, and the failed urls are logged as errors.
Found a bug or need a custom field? Open an issue on the actor's Issues tab in Apify Console, or reach out about a custom build for your exact use case.

