Collect structured product listings from Mercado Livre Brasil search-result pages using the site's slug-based search URL and resilient selectors covering current Poly cards and legacy UI Search layouts. The extractor captures title, URL, image, current and original prices, installments, discount labels, seller, official-store status, shipping, badges, rating, review count, condition, and sold-count text. It deduplicates products and can optionally limit results, filter titles, restrict official stores, or sort by numeric current price.
Use Cases
Use for a keyword or phrase when the required output is the product cards displayed on the corresponding Mercado Livre Brasil results page. By default, return the first 20 deduplicated organic product cards; set maxResults to null when the caller needs every loaded result. For lowest-price requests, provide a model-specific titlePattern and set sortByPrice to true. Set officialStoreOnly to true when official-store listings alone are requested. The workflow is page-local and does not resolve product IDs or open individual product pages.
Automation Flow
- Build the direct URL as
https://lista.mercadolivre.com.br/{normalized-query}: lowercase{query}, replace whitespace runs with hyphens, and URL-encode the path segment. Append?sb=all_mercadolibrefor the all-Mercado-Libre scope when requested. - In one browser call, navigate with
waitUntil: "domcontentloaded", wait about 2 seconds for cards, and execute the evaluator below. SetofficialStoreOnly,titlePattern,sortByPrice, andmaxResultsaccording to the request. The defaultmaxResults=20returns the first 20 organic cards in page order.
(()=>{
const officialStoreOnly=false,titlePattern=null,sortByPrice=false,maxResults=20;
const clean=s=>(s||'').replace(/\s+/g,' ').trim();
const abs=u=>{try{return new URL(u,location.href).href}catch{return u||''}};
const text=(e,ss)=>{for(const s of ss){const v=clean(e.querySelector(s)?.textContent);if(v)return v}return ''};
const attr=(e,ss,as)=>{for(const s of ss){const n=e.querySelector(s);if(!n)continue;for(const a of as){let v=n.getAttribute(a);if(v)return a==='srcset'?abs(v.split(',')[0].trim().split(/\s+/)[0]):abs(v)}}return ''};
const money=(e,ss)=>{for(const s of ss){const n=e.querySelector(s);if(!n)continue;const f=clean(n.querySelector('.andes-money-amount__fraction')?.textContent),c=clean(n.querySelector('.andes-money-amount__cents')?.textContent||'00');if(f){const v=parseFloat(f.replace(/\./g,'').replace(',','.')+'.'+c.replace(/\D/g,''));if(Number.isFinite(v))return v}}return null};
const selectors=['li.ui-search-layout__item','.ui-search-result__wrapper','.poly-card','.andes-card'];
const cards=[...new Set(selectors.flatMap(s=>[...document.querySelectorAll(s)]))];
let re=null;try{re=titlePattern?new RegExp(titlePattern,'i'):null}catch{}
const products=cards.map(card=>{const te=card.querySelector('a.poly-component__title,h2.ui-search-item__title,.ui-search-item__title,[class*="title"] a,a[href*="/MLB-"]');const link=te?.closest('a')||card.querySelector('a[href*="mercadolivre.com.br/MLB"],a[href*="/MLB-"]');const title=clean(te?.textContent||card.querySelector('h2,h3')?.textContent);if(!title||!link||re&&!re.test(title))return null;const seller=text(card,['.poly-component__seller','.ui-search-item__group__element [class*="seller"]','[class*="seller"]']);const official=!!card.querySelector('.poly-component__seller svg[aria-label="Loja oficial"],[aria-label*="Loja oficial" i]')||/loja oficial/i.test(seller)||/loja oficial/i.test(clean(card.textContent));return{title,url:abs(link.href),image:attr(card,['.poly-component__picture','img','picture source'],['src','data-src','data-lazy-src','srcset']),priceCurrent:money(card,['.poly-price__current','.ui-search-price__part']),priceCurrentFull:text(card,['.poly-price__current','.ui-search-price__part']),priceOriginal:money(card,['.poly-price__previous','.poly-price__labels','.andes-money-amount--previous']),installments:text(card,['.poly-price__installments','.ui-search-installments']),discount:text(card,['.poly-price__discount-polylabel','.poly-price__label','.ui-search-price__second-line']),seller,isOfficialStore:official,shipping:text(card,['.poly-component__shipping-v2','.poly-component__shipping','.ui-search-item__shipping','[class*="shipping"]']),rating:text(card,['.poly-reviews__rating','.ui-search-reviews__rating','.poly-component__review-compacted','[class*="rating"]']),reviews:text(card,['.poly-reviews__total','.ui-search-reviews__amount','.poly-component__review-compacted','[class*="reviews"]']),badges:[...card.querySelectorAll('.polylabel-pill,.polylabel-label,.ui-search-item__highlight-label,[class*="badge"]')].map(x=>clean(x.textContent)).filter(Boolean),condition:text(card,['.poly-component__condition','[class*="condition"]']),sold:text(card,['.poly-component__sold-quantity','[class*="sold"]','[class*="quantity"]'])}}).filter(Boolean);
const seen=new Set(),unique=products.filter(p=>!seen.has(p.url)&&seen.add(p.url));let result=officialStoreOnly?unique.filter(p=>p.isOfficialStore):unique;if(sortByPrice)result.sort((a,b)=>(typeof a.priceCurrent==='number'?a.priceCurrent:Infinity)-(typeof b.priceCurrent==='number'?b.priceCurrent:Infinity));if(Number.isInteger(maxResults)&&maxResults>=0)result=result.slice(0,maxResults);return{url:location.href,title:document.title,bodyLength:document.body.innerHTML.length,cardCount:cards.length,officialStoreOnly,titlePattern,sortByPrice,maxResults,products:result,lowestPriceProduct:sortByPrice?result[0]||null:null};
})()Possible Friction Points
- The direct search endpoint is
/{hyphenated-query}; do not visit the homepage or type into the search box first. ?sb=all_mercadolibreselects the observed all-Mercado-Libre scope; it is not itself an official-store filter.- The default result limit is 20, preserving page order after URL deduplication. Set
maxResultstonullfor all loaded cards. - For model-specific searches, supply a caller-generated regular expression matching the requested model; do not hard-code a particular product or title in the skill.
- Official-store status is commonly marked by an SVG with
aria-label="Loja oficial", but card/seller text fallbacks are also used and should be treated as page markers rather than definitive seller identity when markup is absent. - Preserve Poly and UI Search selectors because Mercado Livre may serve different card layouts. Deduplicate by canonical product URL.
- Prices and other labels are localized text. Numeric prices are returned when the amount markup is parseable; displayed text remains available in the full-text fields.
- The evaluator extracts only cards present in the loaded result page; it does not infer products hidden behind pagination or infinite scrolling.
- If cards are absent, inspect the same session for an anti-bot or consent interstitial and wait/retry; no separate bypass endpoint is established.