olx-search

SKILL.md

OLX Brazil Search Skill

Search and analyze listings on OLX Brazil (olx.com.br) via CLI.

Prerequisites

# Use the existing venv (already configured)
PYTHON=/home/diogo/dev/olx-search/.venv/bin/python3

# Or install in any venv:
# pip install cloudscraper browser_cookie3

Quick Reference

Command Description
search -q QUERY Search listings by keyword
search -q QUERY -c CATEGORY Search within a category
details --url URL Get full details of a listing
categories List all categories
categories --parent ID List subcategories
cookies Extract & verify OLX cookies from browser
cookies --export FILE Export cookies to JSON file
get-fields -c CATEGORY_ID Get required fields for publishing in a category
publish -t TITLE -d DESC -c CAT -z CEP Publish a new ad (requires auth)
publish ... --dry-run Preview publish payload without sending
list-ads [--status published|deleted] List your authenticated OLX ads
delete --ad-id LIST_ID [--reason ...] Delete an ad by listId
delete ... --dry-run Preview delete flow without deleting
cep CEP Look up a Brazilian zipcode

Script Location

/home/diogo/.agents/skills/olx-search/scripts/olx.py

Commands

1. Search Listings

$PYTHON scripts/olx.py search -q "iphone 15" --limit 5

Arguments:

Flag Short Description Default
--query -q Search term (empty = browse)
--category -c Category path (friendlyPath) (all categories)
--page -p Page number (1-based) 1
--min-price Minimum price in BRL (none)
--max-price Maximum price in BRL (none)
--sort Sort: price_asc, price_desc, date_desc, date_asc relevance
--limit -l Max results to return 50 (page size)

Search within a category:

# Search cars
$PYTHON scripts/olx.py search -q "civic 2020" -c "autos-e-pecas/carros-vans-e-utilitarios"

# Search phones with price range
$PYTHON scripts/olx.py search -q "iphone" -c "celulares" --min-price 2000 --max-price 5000

# Browse category without search term
$PYTHON scripts/olx.py search -c "imoveis/aluguel" --max-price 3000

Output structure:

{
  "success": true,
  "query": "civic 2020",
  "total_ads": 645,
  "page": 1,
  "page_size": 50,
  "total_pages": 13,
  "results_count": 3,
  "related_categories": [
    {"name": "Carros", "id": "2020", "count": 600, "url": "/autos-e-pecas/carros?q=civic"}
  ],
  "ads": [
    {
      "id": 1439467323,
      "title": "Civic 2020 Touring 1.5 Turbo",
      "price": "R$ 141.990",
      "url": "https://df.olx.com.br/...",
      "location": "Brasilia - DF",
      "location_details": {"city": "Brasilia", "state": "DF", "neighborhood": "Taguatinga"},
      "category": "Carros, vans e utilitarios",
      "professional_ad": true,
      "images": ["https://img.olx.com.br/..."],
      "image_count": 6,
      "date": 1769523112,
      "properties": {
        "vehicle_brand": "Honda",
        "vehicle_model": "Honda Sedan Touring 1.5 Turbo",
        "regdate": "2020",
        "mileage": "0",
        "fuel": "Gasolina",
        "gearbox": "Automatico"
      },
      "olx_pay": false,
      "olx_delivery": false
    }
  ]
}

2. Get Listing Details

$PYTHON scripts/olx.py details --url "https://df.olx.com.br/distrito-federal/carros/civic-2020-1439467323"

Output structure:

{
  "success": true,
  "url": "https://...",
  "id": 1439467323,
  "title": "Civic 2020 Touring",
  "description": "Full text description...",
  "price": "141990",
  "currency": "BRL",
  "images": ["https://img.olx.com.br/..."],
  "seller": "username",
  "item_type": "Car",
  "metadata": {
    "list_id": 1439467323,
    "category_id": 2020,
    "parent_category_id": 2000,
    "city_id": 4530,
    "state_id": "61"
  }
}

3. Browse Categories

# List all top-level categories
$PYTHON scripts/olx.py categories

# List subcategories of "Autos" (id=2000)
$PYTHON scripts/olx.py categories --parent 2000

# Search categories by name
$PYTHON scripts/olx.py categories -s "celular"

Key category IDs:

ID Name Path
1000 Imoveis imoveis
2000 Autos autos-e-pecas
2020 Carros autos-e-pecas/carros-vans-e-utilitarios
3000 Eletronicos eletronicos-e-celulares
3060 Celulares celulares
4000 Para a sua casa para-a-sua-casa
5000 Esportes e lazer esportes-e-lazer

See references/categories.json for the full list of 153 categories.

4. Extract & Verify Cookies

Automatically extracts OLX cookies from the user's browser (Chromium, Chrome, Brave, Firefox, Edge). Cookies are needed for authenticated operations (publishing ads, getting form fields).

# Auto-detect browser and verify authentication
$PYTHON scripts/olx.py cookies

# Use a specific browser
$PYTHON scripts/olx.py cookies --browser brave

# Export cookies to a file
$PYTHON scripts/olx.py cookies --export ~/olx-cookies.json

Output:

{
  "success": true,
  "browser": "chromium",
  "cookie_count": 63,
  "authenticated": true,
  "user": {
    "name": "User Name",
    "email": "user@example.com",
    "phone": "21999999999",
    "zipcode": "01001000",
    "verified": true
  }
}

Cookie priority chain:

  1. --cookies-file FILE (explicit file path)
  2. Cached cookies (auto-saved from last extraction)
  3. Auto-extract from browser (tries chromium → chrome → brave → firefox → edge → opera)

Important: The user must be logged in to olx.com.br in their browser for auth cookies to be available.

5. Get Category Fields (for Publishing)

Returns the required and optional fields for publishing an ad in a specific category.

# Get fields for phones (category 3060)
$PYTHON scripts/olx.py get-fields -c 3060

# Get fields for cars (category 2020)
$PYTHON scripts/olx.py get-fields -c 2020

# Use a specific cookies file
$PYTHON scripts/olx.py get-fields -c 3060 --cookies-file ~/olx-cookies.json

Output:

{
  "success": true,
  "category": "3060",
  "field_count": 10,
  "fields": [
    {
      "code": "cellphone_brand",
      "param_key": "electronics_brand",
      "label": "Marca",
      "required": true,
      "type": "single_selection",
      "datasource_url": "https://ck-gw.olx.com.br/attributes/cellphone_brand/values?format=remote"
    }
  ]
}

6. Publish an Ad

Create a new listing on OLX. Requires authentication (user must be logged in to OLX in their browser).

Workflow: First use get-fields to discover required fields for the category, then publish.

# Step 1: Find the right category
$PYTHON scripts/olx.py categories -s "informatica"

# Step 2: Get required fields for that category
$PYTHON scripts/olx.py get-fields -c 19060

# Step 3: Dry-run to preview the payload
$PYTHON scripts/olx.py publish \
  -t "Placa Mae Asus Maximus Hero IX" \
  -d "Placa mãe com defeito no soquete. Apenas para retirada de peças." \
  -c 19060 \
  --price 100 \
  -z 01001000 \
  --phone-hidden \
  --fields '{"info_components_condition": "2", "info_components_type": "10", "exchange": "1"}' \
  --dry-run

# Step 4: Publish for real (remove --dry-run)
$PYTHON scripts/olx.py publish \
  -t "Placa Mae Asus Maximus Hero IX" \
  -d "Placa mãe com defeito no soquete." \
  -c 19060 \
  --price 100 \
  -z 01001000 \
  --phone-hidden \
  --fields '{"info_components_condition": "2", "info_components_type": "10"}' \
  --images photo1.jpg photo2.png

Arguments:

Flag Short Description Required
--title -t Ad title (max 90 chars) Yes
--description -d Ad description text Yes
--category -c Category ID (numeric) Yes
--zipcode -z CEP (8 digits) Yes
--price Price in BRL (integer) No
--images Image file paths to upload No
--fields Category-specific fields as JSON No
--phone-hidden Hide phone number No
--condominio Condo fee in BRL (real estate) No
--iptu IPTU tax in BRL (real estate) No
--dry-run Preview payload without publishing No
--browser -b Browser for cookie extraction No
--cookies-file Path to cookies JSON file No

Success output:

{
  "success": true,
  "status_code": 200,
  "ad_id": 1750090069,
  "response": {"ad_id": 1750090069, "show_hv": false},
  "request_id": "4e3d6402-b6dc-42c4-9cf8-5f1ba13ed481"
}

Important notes on --fields:

  • Fields go FLAT into the API payload (not nested under a key)
  • Use get-fields -c CATEGORY_ID to discover what fields are needed
  • Each field has a code (the key to use) and options (valid values)
  • Example: {"info_components_condition": "2", "exchange": "1"}
  • Fields can also be passed as a path to a JSON file

Image upload:

  • Images are uploaded to apigw.olx.com.br/ai/image before the ad is created
  • Supported formats: .jpg, .jpeg, .png, .webp
  • The upload response id is used as "{id}.jpg" in the ad payload

7. List Your Ads

List authenticated user's ads from OLX MyData API.

# List published ads (default)
$PYTHON scripts/olx.py list-ads

# List deleted ads
$PYTHON scripts/olx.py list-ads --status deleted

# Use explicit cookies file
$PYTHON scripts/olx.py list-ads --cookies-file ~/olx-cookies.json

Arguments:

Flag Description Default
--status Ad status: published or deleted published
--browser / -b Browser for cookie extraction auto
--cookies-file Path to cookies JSON file (none)

Output fields per ad:

  • listId (ad list id)
  • adId (legacyAdId)
  • title
  • status
  • category
  • price
  • date
  • url
  • views

8. Delete an Ad

Delete one of your ads by listId using the captured 2-step OLX deletion flow.

# Dry-run first (recommended)
$PYTHON scripts/olx.py delete --ad-id 1476080677 --dry-run

# Delete for real
$PYTHON scripts/olx.py delete --ad-id 1476080677 --reason other_reason

# Other reasons
$PYTHON scripts/olx.py delete --ad-id 1476080677 --reason sold_in_olx
$PYTHON scripts/olx.py delete --ad-id 1476080677 --reason sold_elsewhere
$PYTHON scripts/olx.py delete --ad-id 1476080677 --reason gave_up_selling

Arguments:

Flag Description Required
--ad-id Ad listId to delete (get from list-ads) Yes
--reason Reason: sold_in_olx, sold_elsewhere, gave_up_selling, other_reason No
--dry-run Show flow without deleting No
--browser / -b Browser for cookie extraction No
--cookies-file Path to cookies JSON file No

Flow used:

  1. Resolve listIdlegacyAdId via list-ads/mydata
  2. GET upsell page (adquirir.olx.com.br/destaques?...)
  3. GET delete completion endpoint (pos.olx.com.br/complete?...)
  4. Success is validated when response URL contains deletion-success

9. Look Up CEP (Zipcode)

Validate a Brazilian zipcode and get location data.

$PYTHON scripts/olx.py cep 01001000
$PYTHON scripts/olx.py cep 01001-000

Common Workflows

Price comparison

# Search, then compare prices for same product across sellers
$PYTHON scripts/olx.py search -q "macbook pro m3" --sort price_asc --limit 10

Market analysis

# Get all listings in a category for a region
$PYTHON scripts/olx.py search -c "imoveis/aluguel" --min-price 1000 --max-price 3000 --limit 50

Listing investigation

# First search, then get details on interesting listings
$PYTHON scripts/olx.py search -q "mesa escritorio" --limit 5
# Then get details on a specific ad
$PYTHON scripts/olx.py details --url "https://..."

Publish an ad (full workflow)

# 1. Find category ID
$PYTHON scripts/olx.py categories -s "celular"
# 2. Get required fields for that category
$PYTHON scripts/olx.py get-fields -c 3060
# 3. Validate your CEP
$PYTHON scripts/olx.py cep 01001000
# 4. Dry-run to check payload
$PYTHON scripts/olx.py publish -t "iPhone 14" -d "iPhone 14 128GB" -c 3060 -z 01001000 --price 3500 --fields '{"cellphone_brand": "2"}' --dry-run
# 5. Publish for real
$PYTHON scripts/olx.py publish -t "iPhone 14" -d "iPhone 14 128GB" -c 3060 -z 01001000 --price 3500 --fields '{"cellphone_brand": "2"}' --images iphone.jpg

Technical Notes

  • Each search page returns up to 50 results
  • Use --page N for pagination (page 2, 3, etc.)
  • The date field in ads is a Unix timestamp
  • Properties vary by category (cars have vehicle-specific fields, phones have storage/brand, etc.)
  • Rate limit: add a few seconds delay between requests to avoid blocking
  • Cloudflare is bypassed automatically via cloudscraper
  • Cookies are auto-extracted from the user's browser via browser_cookie3
  • Extracted cookies are cached at ~/.agents/skills/olx-search/.cookies_cache.json
  • Commands that need auth (get-fields, publish) auto-extract cookies if no --cookies-file is given
  • Commands that need auth (get-fields, publish, list-ads, delete) auto-extract cookies if no --cookies-file is given
  • search, details, categories, and cep do NOT require authentication
  • publish uses the real OLX ad insertion API (POST /ai-bff/v2/anuncio/)
  • list-ads uses GET /mydata/v1/data with OLX team key and account origin headers
  • delete uses the 2-step flow: adquirir.olx.com.br/destaques then pos.olx.com.br/complete
  • Image upload uses POST /ai/image with multipart form data
  • The publish payload format was reverse-engineered from a real successful publish (verified HTTP 200)

Error Handling

Errors return JSON with an error field:

{"error": "Failed to fetch page (HTTP 403)", "url": "..."}

Exit code 1 on errors, 0 on success.

Weekly Installs
2
GitHub Stars
2
First Seen
Feb 8, 2026
Installed on
kilo2
crush2
amp2
opencode2
kimi-cli2
droid2