A developer building a LangChain pipeline that reads Shopify product pages needs structured product data, including name, price, availability, and description, before passing it into an agent or retrieval layer. Shopify pages are JavaScript-rendered and their HTML structure changes with theme updates, so maintaining a custom scraper or CSS selector set is a recurring maintenance burden. Each theme change is another debugging session, and the extracted data still arrives as raw values before anything reaches LangChain. EnConvert’s Distill endpoint accepts up to 50 Shopify product URLs with a schema defining the fields you need and returns a results array with each URL’s extracted data normalized to exactly that schema in one synchronous call, with no HTML parsing or preprocessing required.
How to Summarise Shopify Products with LangChain
How to extract structured Shopify product data into a LangChain pipeline with EnConvert Distill, returning schema-matched fields from product pages in one call
Get API keyExample
python
import os
import requests
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
# Step 1: Define target Shopify product URLs and the extraction schema
product_urls = [url.strip() for url in os.environ["SHOPIFY_PRODUCT_URLS"].split(",")] # public Shopify product page URLs
schema = {
"name": "The product's display name",
"price": "The current selling price, including currency if shown",
"availability": "Whether the product is in stock, sold out, or otherwise unavailable",
"description": "The product description in plain prose",
}
# Step 2: Call Distill — synchronous, no job_id, no polling, no download step
# Distill requires a paid plan; the free tier returns 402
response = requests.post(
"https://api.enconvert.com/v2/distill",
headers={
"X-API-Key": os.environ["ENCONVERT_API_KEY"],
"Content-Type": "application/json",
},
json={
"urls": product_urls,
"schema": schema,
},
timeout=120, # increase for larger batches
)
if response.status_code == 402:
raise RuntimeError("Distill requires a paid plan")
response.raise_for_status()
# Step 3: Parse results — failed pages arrive as rows, not as request errors
products = []
for result in response.json()["results"]:
if result["status"] != "completed":
print(f"Skipped {result['url']}: {result['status']}")
continue
if result.get("render_quality", 1.0) < 0.5:
# Low render_quality flags anti-bot challenges or login walls
print(f"Low render quality for {result['url']}: {result['render_quality']}")
continue
# result["data"] contains exactly the schema keys above
products.append({"url": result["url"], **(result.get("data") or {})})
if not products:
raise RuntimeError("No Shopify products were extracted successfully")
print(f"Extracted {len(products)} products")
# Step 4: Pass the structured product data into a LangChain chain
prompt = ChatPromptTemplate.from_messages([
(
"system",
"Summarise Shopify product records for a merchandising review. "
"Use only the supplied structured data. Do not invent availability, pricing, or product features.",
),
("human", "Summarise these products:\n\n{products}"),
])
chain = prompt | ChatOpenAI(model="gpt-4.1", api_key=os.environ["OPENAI_API_KEY"]) | StrOutputParser()
summary = chain.invoke({
"products": "\n\n".join(str(p) for p in products)
})
print(summary)
What you get back
The Distill endpoint returns a results array with one entry per URL, each containing a data object normalized to exactly the schema’s keys — name, price, availability, and description — regardless of the page’s underlying HTML structure or JavaScript rendering. Maintaining a custom CSS selector set or HTML parser for Shopify pages breaks with every theme update and requires a separate preprocessing step before any structured data reaches LangChain.
Distill runs on paid plans only, and the free tier returns a 402 for this endpoint, so the free key covers EnConvert’s other endpoints.