Extract Products from Presentéum Collections and Search

Site presenteum.comTask extract-products-from-collectionVersion v8Updated Nov 1, 2026Category ecommerce

Retrieve product links, titles, prices, availability, visible text, product types, image URLs, and individual product metadata from Presentéum collections, search results, or Shopify product JSON. This skill was captured from a live agent session on presenteum.com and is published here as a reusable recipe for agents.

NoteSelectors and URL schemes drift as sites change. A skill is a snapshot of what worked when it was captured, not a contract — agents re-learn it when it stops working.

Extract structured product information from any Presentéum collection, predictive search result, or individual product JSON endpoint. Collection extraction includes product URLs, titles, prices, availability, visible description text, product types, and image URLs. Search extraction returns matching product titles and URLs plus available metadata. Individual product extraction is useful for checking a specific tile's product metadata and variant availability before investigating shipping eligibility.

Use Cases

Use when the caller provides a Presentéum collection handle or collection URL and needs the products currently listed there, when the caller provides a product-name or keyword query and needs matching products, or when a known product handle must be inspected directly. Product JSON availability alone does not prove that a product ships to a particular destination; destination-specific shipping eligibility may require the site's cart or checkout flow.

Automation Flow

  1. For a collection, derive the collection handle from the supplied URL or use the supplied handle directly.
  2. Navigate directly to https://presenteum.com/collections/{collection-handle}/products.json?limit=50 with waitUntil: "domcontentloaded", then run the collection extractor below in the same browser call.
  3. For keyword lookup, URL-encode {query} and navigate directly to https://presenteum.com/search/suggest.json?q={query}&resources[type]=product,page,article&resources[limit]={limit} with waitUntil: "domcontentloaded", then run the search extractor below in the same browser call. Use a limit such as 10 unless the caller requests another value.
  4. When a product handle is already known, navigate directly to https://presenteum.com/products/{product-handle}.json with waitUntil: "domcontentloaded", then run the individual-product extractor below. Do not guess a handle; resolve it through predictive search first when only a product name is supplied.

Collection extractor:

(() => {
const data = JSON.parse(document.body.innerText);
return (data.products || []).map(p => {
  const variants = Array.isArray(p.variants) ? p.variants : [];
  const image = Array.isArray(p.images) && p.images[0] ? p.images[0].src : null;
  const body = (p.body_html || '').replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 160);
  return {
    href: p.handle ? `/products/${p.handle}` : null,
    text: (p.title || '').replace(/\s+/g, ' ').trim().slice(0, 140),
    image,
    title: p.title || null,
    price: variants[0] ? variants[0].price : null,
    available: variants.some(v => v.available === true),
    productType: p.product_type || null,
    body
  };
});
})()

Search extractor:

(() => {
const data = JSON.parse(document.body.innerText);
const results = data.resources && data.resources.results || {};
return (results.products || []).map(p => ({
  title: (p.title || '').replace(/\s+/g, ' ').trim(),
  url: p.url || null,
  handle: p.handle || null,
  price: p.price || (p.variants && p.variants[0] ? p.variants[0].price : null),
  image: p.image || (p.featured_image && (p.featured_image.url || p.featured_image)) || null
}));
})()

Individual-product extractor:

(() => {
const data = JSON.parse(document.body.innerText);
const p = data.product || {};
const variants = Array.isArray(p.variants) ? p.variants : [];
const body = (p.body_html || '').replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 220);
return {
  handle: p.handle || null,
  title: p.title || null,
  vendor: p.vendor || null,
  productType: p.product_type || null,
  price: variants[0] ? variants[0].price : null,
  available: variants.some(v => v.available === true),
  variants: variants.map(v => ({id: v.id || null, title: v.title || null, price: v.price || null, available: v.available === true})),
  body
};
})()

Possible Friction Points

  • Presentéum exposes collection-scoped Shopify JSON at /collections/{collection-handle}/products.json?limit=50; use it instead of scraping repeated product cards.
  • Individual products expose Shopify JSON at /products/{product-handle}.json; it returns a product object with variants, vendor, description, and availability.
  • Product handles are opaque enough that they must come from supplied input or a search result; never infer one from an arbitrary product name.
  • Product JSON availability indicates whether at least one variant is available, not whether the item ships to a requested country. Do not report destination shipping eligibility without evidence from cart, checkout, or an explicit shipping policy.
  • Collection responses use products; product handles are suitable for constructing /products/{handle} URLs.
  • price is taken from the first variant, while available is true when any variant is marked available.
  • image is taken from the first product image and is null when no image is present.
  • body is plain text derived from body_html, normalized, and truncated; it may be empty.
  • Collection endpoints support larger paged reads such as /collections/all/products.json?limit=250&page={page}. Iterate pages and concatenate results when more than one response is needed; do not assume one response is exhaustive.
  • Predictive search uses /search/suggest.json with q={query}, resources[type]=product,page,article, and resources[limit]={limit}. Product matches are under resources.results.products; pages and articles are separate.
  • Search URLs must encode the caller's query. Some responses omit handle, price, or image; preserve those fields as null.

Call it

GET https://production-sfo.browserless.io/skills?token=TOKEN-HERE&domain=presenteum.com&task=extract-products-from-collection