A JSON-First Scraper for Avito.ma Listings
MuLIAICHI/avito-maroc-scraper targets structured extraction from Avito.ma search and category pages by reading the site's documented Next.js data payload rather than relying on CSS selectors.
When marketplace data lives behind a moving interface
A classifieds marketplace can be valuable for price research, inventory monitoring, or localized search tools, but its web interface is not necessarily a stable data interface. Listing cards, labels, and page layout can change independently of the fields a downstream application needs. Builders then face a familiar maintenance problem: a scraper tied tightly to visual page structure may break when selectors change.
MuLIAICHI/avito-maroc-scraper is an Apify Actor aimed at Avito.ma, a Moroccan classifieds platform. Its README positions the project as a structured extractor that can start from Avito search or category URLs, follow result pagination, and return listing records as JSON. The documented target categories include vehicles, real estate, electronics, and jobs.
The core implementation choice described by the project is to use Avito's Next.js __NEXT_DATA__ payload instead of CSS selectors. In plain terms, CSS selectors identify visible HTML elements such as a title or price label. The __NEXT_DATA__ payload is page data made available by a Next.js application. The repository presents this JSON-first approach as a way to reduce dependence on the presentation layer.
A bounded workflow: URLs in, listing records out
The documented input is deliberately small. startUrls accepts an array of Avito search or category URLs, while maxItems sets the maximum number of listings to extract and defaults to 100. A proxyConfiguration object is also available for routing requests through a proxy service.
That model makes the actor suitable for workflows that begin with a narrow market question. A user might provide one URL for cars for sale across Morocco and another for apartments in Casablanca, then set a limit appropriate to the task. The README's example uses those two kinds of starting points and requests up to 500 items.
From there, the actor is documented to handle search-result pagination. Rather than limiting extraction to the first page of a search, it can navigate result pages as it collects listings. The README does not document the exact paging algorithm or request concurrency, so those implementation details should not be assumed. What is clear is the intended operational path: begin at supplied discovery URLs, collect listings across results, and write normalized records.
The sample output shows the shape of a listing. It includes a source url, an id, title, price, currency, location, description, image URLs, and a scrape timestamp. Location is represented as a nested object with city and area. Images are represented as an array, and the project says it retrieves full-resolution URLs rather than thumbnails.
One especially useful detail is attributes. The field is an object whose keys can vary by category. The vehicle example includes brand, model, model year, mileage, fuel type, and transmission. That is a practical representation for a marketplace spanning unrelated kinds of listings. A vehicle has mileage, while a property may have room count. Forcing both into one rigid flat schema can produce many empty columns or discard category-specific information. Keeping common fields alongside dynamic attributes preserves more of the original listing context.
Parsing application data rather than page styling
The README makes a strong distinction between data payload parsing and selector-based scraping. The benefit is not that JSON is inherently complete or permanent. It is that the extraction logic can be aligned with the structured data the application provides instead of with its current visual arrangement.
For builders, this suggests a useful design principle: distinguish the data model from the rendered interface whenever a site exposes both. The interface is optimized for people browsing listings. A structured payload can be a more direct fit for a pipeline that needs fields such as currency, city, images, and category attributes.
There is still a tradeoff. The project's own operational notes say Avito.ma uses anti-bot measures and that attempts to collect thousands of listings without residential IPs can lead to captchas and blocks. The README says datacenter proxies may work for small, targeted runs, while recommending Apify Residential Proxies for production-scale work. Proxy selection is therefore part of the operating model, not an incidental configuration detail.
That guidance also points to a more disciplined way to use a tool like this. Begin with specific category or search URLs and a limited maxItems value when exploring a question. Scale only when the collection scope, proxy configuration, and downstream handling of the resulting data are clear. The repository documents proxy recommendations, but it does not claim that any configuration eliminates access controls or guarantees uninterrupted runs.
A JavaScript crawler stack with browser support
The repository metadata lists HTML as the primary repository language. Its package.json, however, confirms a Node.js-oriented runtime setup: the start script runs node src/main.js, and the package uses ECMAScript modules via "type": "module".
The confirmed dependencies are centered on Apify and Crawlee. apify provides the Actor-oriented platform integration described in the README. @crawlee/cheerio and @crawlee/playwright are crawler packages, with the former associated with HTML parsing and the latter with Playwright-backed browser crawling. playwright is included directly, and the post-install script installs Playwright browsers through Crawlee.
Those dependencies support the project’s stated blend of page retrieval and structured data extraction. The manifest alone does not establish exactly which crawler is used on each path, but it does verify that the project includes both HTML parsing and browser automation tooling. That can be useful for a site where a browser-capable workflow may be needed to obtain application-rendered or protected pages, while structured payload parsing handles the actual listing fields.
Development tooling is also present. The manifest lists Vitest for tests, ESLint with an Apify configuration for linting, and Prettier for formatting. Their presence verifies that the project is set up with commands for testing, linting, and formatting. It does not, by itself, verify test coverage or passing test status.
Normalized output is the real interface
The repository describes its JSON output as suitable for uses such as analytics pipelines, retrieval-augmented generation systems, vector databases, and agent tools. The concrete takeaway is broader than any one AI use case: structured output makes a collection run easier to consume than an archive of raw pages.
For market analysis, price, location, and category attributes can be retained together. For an application search feature, a record’s title, description, images, and source URL offer a useful starting payload. For category-specific analysis, the dynamic attributes object avoids pretending that every listing type has the same properties.
The project also demonstrates an important boundary for data tooling. A scraper can standardize data after collection, but it cannot make the upstream marketplace static. Schema variations across categories, paginated results, anti-bot controls, and changes to the site’s application data are all practical conditions to plan for. The README notes that users can report structural changes through the Apify platform, which reflects that ongoing maintenance reality.
For builders working with Moroccan classifieds data, the value proposition is straightforward: configure a set of Avito URLs, set an item limit, use an appropriate proxy configuration, and receive listing-oriented JSON with shared fields and category-specific attributes. Inspect the verified repository at https://github.com/MuLIAICHI/avito-maroc-scraper for the documented inputs, output example, and runtime setup.
Turn your GitHub repository into a story worth sharing.
Connect a public repository, generate a reviewable draft, and publish it with Reather.
