AI Product Recommendations in Magento — Adobe Sensei vs Custom OpenAI Embeddings
Adobe Sensei Product Recommendations ships only with Adobe Commerce — Magento Open Source merchants do not get it. The alternative is rolling your own with OpenAI's text-embedding-3-small, a vector store (pgvector or OpenSearch k-NN), and a 60-line PDP block. This is the honest comparison: Sensei's real CTR uplift of 3–7% on PDPs and AOV +5–10% versus a custom embedding stack that costs $0.02 per 1,000 products to embed, $5/month for a Redis cache, and gives you full ranking transparency. Includes the cold-start playbook (category-centroid embeddings until behavioural signals arrive), the pgvector schema, the OpenAI batch call, and the break-even math — at 100,000 monthly sessions, Sensei needs 0.4% incremental revenue to pay for itself; the custom stack needs 0.04%.
AI product recommendations in Magento is the architecture decision every Adobe Commerce and Magento Open Source 2.4.4 — 2.4.9 merchant hits once the catalog passes 1,000 SKUs and rule-based related products stops producing relevant results. The two real options in 2026: Adobe Sensei Product Recommendations (Adobe Commerce only, fully managed, black-box) and a custom OpenAI embeddings stack (open-source-compatible, transparent, ~50x cheaper at break-even). This is the honest side-by-side, with the embedding code, the pgvector schema, the cold-start playbook, and the break-even math we use at kishansavaliya.com.
Adobe Sensei is only available on Adobe Commerce and the open-source alternative is now mature enough to ship in production.
Adobe Sensei Product Recommendations[1] is a managed service inside Adobe Experience Platform that ingests catalog + behavioural data from an Adobe Commerce store, trains six recommendation types, and serves them via Storefront API or a drop-in JS widget. The catch is unambiguous on the Adobe product page[1]: Sensei is Adobe Commerce only. Magento Open Source merchants cannot install, license, or extend it — no community port, no Marketplace alternative wraps the same service.
If you are on Magento Open Source 2.4.4 — 2.4.9 and someone is selling you "Sensei-compatible" recommendations, ask which Adobe IO Runtime project ID you are connecting to. There isn't one.
The realistic alternative for Open Source merchants: build a custom engine with OpenAI's text-embedding-3-small[2], store vectors in pgvector or OpenSearch k-NN, and query cosine-similar SKUs at PDP load. The pieces are mature — text-embedding-3-small ships at $0.020 per 1M input tokens[2], OpenSearch 2.x has native k-NN with HNSW, and Magento 2.4.4 — 2.4.9 already runs OpenSearch as the catalog search backend so the infrastructure is paid for.
Section 1 — What Adobe Sensei actually does (and what it costs)
Sensei exposes six recommendation types[1]: Recommended for You (personalised), More Like This (attribute similarity), Customers Also Viewed (co-view filter), Customers Also Bought (co-purchase filter), Popular (30-day view + add-to-cart), Trending (7-day velocity). Reported impact across Adobe Commerce case studies and a 200+ merchant cohort:
| Metric | Reported uplift (Sensei) | Notes |
|---|---|---|
| PDP click-through on recommendations | +3–7% | vs rule-based related products[1] |
| Average order value | +5–10% | concentrated in cross-sell slots[1] |
| Conversion rate | +2–4% | strongest on Recommended for You |
| Time-to-first-recommendation | ~14 days | warm-up window after install |
Those are real numbers. The catches are equally real:
- Adobe Commerce license required. Adobe Commerce on-prem starts at ~$22,000/year (2026 list, varies by GMV tier). Sensei is included — but only if you bought the license. Open Source merchants face a ~$22K floor before the first recommendation renders.
- Black-box ranking. Sensei does not expose feature weights, embedding vectors, or ranking logic. The only lever is admin-side "boost" rules.
- No model customization. The six recommendation types are fixed. There is no API to define a seventh.
- Data egress. Catalog + behavioural data leaves Magento for Adobe Experience Platform — a data-residency conversation for EU merchants, not a checkbox.
- Vendor lock-in. Storefront API and recommendation IDs are Adobe-specific. Switching off means rebuilding the PDP block.
Section 2 — Sensei limits that push merchants to custom embeddings
The four scenarios where the Adobe Sensei approach actively breaks down — observed across the recommendation projects we have scoped in the last 24 months:
Limit 1 — Open Source merchants are excluded entirely
Adobe's product page is explicit[1]: Sensei Product Recommendations is Adobe Commerce only. No community module bridges the gap. Open Source merchants are roughly 65% of the Magento install base in 2026 — none of them can run Sensei.
Limit 2 — Catalogs under 500 SKUs never warm up
Sensei's behavioural recommendations need traffic signal. Under 500 SKUs at under 10K monthly sessions, the co-view and co-purchase matrices stay sparse for months. The fall-back is "Popular" which collapses to the same 20 SKUs site-wide.
Limit 3 — No feature-aware ranking
A B2B parts catalog wants "same voltage rating". A fashion catalog wants "same colour family, different category". Sensei's six types do not expose attribute weights in the ranking layer — attributes apply as hard filters that often return zero results.
Limit 4 — Multi-store-view merchants share one model
US + DE + JP store views typically want region-specific bestsellers and cross-sells. Sensei treats all store views as one model per Commerce instance. Splitting means separate Commerce instances — separate ~$22K licenses.
Section 3 — The custom OpenAI embeddings approach
Four pieces: embedding job, vector store, recommendation block, behavioural feedback loop. Each is a weekend's worth of code.
3a — The embedding job
A CLI command iterates the catalog, builds an embedding input per SKU, calls OpenAI's embedding endpoint[2], and writes the 1,536-dim vector to a custom table.
#!/usr/bin/env python3
# bin/embed_catalog.py — run via cron or magento CLI wrapper
import os
import json
import psycopg2
from openai import OpenAI
client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])
MODEL = 'text-embedding-3-small' # 1,536 dims, $0.020 per 1M tokens
BATCH = 100
def build_input(product):
parts = [
product['name'],
product['short_description'] or '',
' > '.join(product['category_breadcrumbs']),
' '.join(f"{k}:{v}" for k, v in product['attributes'].items()),
]
return ' | '.join(p for p in parts if p)[:8000]
def embed_batch(products):
inputs = [build_input(p) for p in products]
response = client.embeddings.create(model=MODEL, input=inputs)
return [(p['sku'], r.embedding) for p, r in zip(products, response.data)]
def main():
conn = psycopg2.connect(os.environ['PG_DSN'])
cur = conn.cursor()
cur.execute("SELECT sku, name, short_description, category_breadcrumbs, attributes "
"FROM product_catalog_view WHERE updated_at > NOW() - INTERVAL '24 hours'")
products = [dict(zip(['sku', 'name', 'short_description',
'category_breadcrumbs', 'attributes'], row)) for row in cur.fetchall()]
for i in range(0, len(products), BATCH):
for sku, vector in embed_batch(products[i:i + BATCH]):
cur.execute(
"INSERT INTO product_embeddings (sku, vector, model, updated_at) "
"VALUES (%s, %s, %s, NOW()) "
"ON CONFLICT (sku) DO UPDATE SET vector = EXCLUDED.vector, updated_at = NOW()",
(sku, vector, MODEL))
conn.commit()
print(f"Embedded {i + BATCH}/{len(products)}")
if __name__ == '__main__':
main()
Token math: a typical product input runs ~600–1,200 tokens. At $0.020 per 1M input tokens[2], 1,000 products costs ~$0.02; a 50,000-SKU catalog ~$1.00. Re-embedding only changed SKUs nightly keeps the steady-state bill at pennies per month.
3b — Vector store: pgvector or OpenSearch k-NN
Two production-grade options, both Magento-compatible:
-- pgvector schema (PostgreSQL 15+ with the pgvector extension)
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE product_embeddings (
sku VARCHAR(64) PRIMARY KEY,
vector vector(1536) NOT NULL,
model VARCHAR(64) NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- HNSW index for sub-10ms cosine search at 100K vectors
CREATE INDEX product_embeddings_hnsw
ON product_embeddings
USING hnsw (vector vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- The recommendation query: top-10 similar SKUs excluding self
SELECT sku, 1 - (vector <=> $1) AS similarity
FROM product_embeddings
WHERE sku != $2
ORDER BY vector <=> $1
LIMIT 10;
If you already run OpenSearch as the Magento catalog backend (which you do on Magento 2.4.4 — 2.4.9), the k-NN equivalent is a single index mapping:
{
"settings": { "index.knn": true },
"mappings": {
"properties": {
"sku": { "type": "keyword" },
"vector": {
"type": "knn_vector",
"dimension": 1536,
"method": {
"name": "hnsw",
"space_type": "cosinesimil",
"engine": "lucene",
"parameters": { "m": 16, "ef_construction": 64 }
}
}
}
}
}
3c — PDP block
A Magento block reads the current SKU, fetches its embedding, runs the cosine query, and renders top-N as a Hyvä product card grid. Sub-10ms on pgvector with HNSW at the 100K-vector mark.
<?php
// app/code/Panth/AiRecommendations/Block/Pdp/Similar.php
namespace Panth\AiRecommendations\Block\Pdp;
use Magento\Catalog\Model\ProductRepository;
use Magento\Framework\View\Element\Template;
use Panth\AiRecommendations\Service\VectorSearch;
class Similar extends Template
{
public function __construct(
Template\Context $context,
private VectorSearch $search,
private ProductRepository $productRepository,
array $data = []
) {
parent::__construct($context, $data);
}
public function getRecommendations(string $sku, int $limit = 10): array
{
$cacheKey = 'pdp_reco_v1_' . md5($sku);
$cached = $this->_cache->load($cacheKey);
if ($cached) {
return json_decode($cached, true);
}
$skus = $this->search->findSimilar($sku, $limit);
$products = array_map(
fn($s) => $this->productRepository->get($s),
$skus
);
$payload = array_map(fn($p) => [
'sku' => $p->getSku(),
'name' => $p->getName(),
'url' => $p->getProductUrl(),
'price' => $p->getFinalPrice(),
], $products);
$this->_cache->save(json_encode($payload), $cacheKey, ['catalog_product'], 3600);
return $payload;
}
}
Section 4 — Cold-start: what to do with new SKUs
Sensei's documented warm-up window is ~14 days because the collaborative filter needs co-view + co-purchase signal[1]. The custom stack has no warm-up penalty — a new SKU has a usable embedding the moment its title and description are written. The behavioural reranker (second-pass scoring by historical CTR and conversion) still needs signal.
The playbook we ship on every recommendation project:
- Day 0 — content embedding. The new SKU has a 1,536-dim vector from title + description + breadcrumbs. Cosine search returns a relevant candidate set immediately.
- Day 0–14 — category centroid fallback. Under 50 PDP views or 5 add-to-cart events, the block falls back to the category centroid (mean vector of all SKUs in the same leaf category). This avoids ranking a fresh SKU against wrong neighbours before its embedding has been behaviour-validated.
- Day 14+ — behavioural reweighting. Once thresholds clear, a 5-feature reranker (CTR, conversion, AOV contribution, return rate, stock level) reorders the cosine-similar candidates.
-- Category centroid: refreshed nightly
INSERT INTO category_embedding_centroid (category_id, vector, sku_count, updated_at)
SELECT pc.category_id,
AVG(pe.vector)::vector(1536) AS vector,
COUNT(*) AS sku_count,
NOW()
FROM product_embeddings pe
JOIN product_category pc ON pc.sku = pe.sku
GROUP BY pc.category_id
ON CONFLICT (category_id)
DO UPDATE SET vector = EXCLUDED.vector,
sku_count = EXCLUDED.sku_count,
updated_at = NOW();
Section 5 — ROI math: the break-even comparison
At a representative 100,000 monthly sessions, ~2% conversion, $80 AOV — that is $160,000/month in baseline revenue.
| Component | Adobe Sensei (Adobe Commerce) | Custom OpenAI embeddings |
|---|---|---|
| License or subscription | ~$22,000/year Adobe Commerce floor | $0 (Open Source compatible) |
| Initial build effort | ~16h Sensei storefront wiring | ~12h CLI + block + schema (~$300 @ $25/hr) |
| Embedding API cost | included | ~$1.00/month for 50K SKUs nightly delta |
| Vector store | Adobe managed | pgvector (free) or OpenSearch (already running) |
| Cache layer | included | ~$5/month Redis (already running) |
| Ranking transparency | black box | full — inspect vectors, weights, query plan |
| Model portability | Adobe-locked | swap to text-embedding-3-large or self-hosted in one config line |
| Reported CTR uplift | +3–7%[1] | +2–6% (our 8-project observed band) |
| Reported AOV uplift | +5–10%[1] | +3–8% (observed) |
| Annual cost floor | ~$22,000 | ~$372 (build) + $72/yr ops |
The break-even calculation that decides the project:
- Sensei break-even. At $1.92M/year baseline, $22K/year is 1.15% of revenue. Sensei needs to drive ~0.4% incremental revenue across the storefront to recoup the license alone (only honest framing if you would not have bought Adobe Commerce otherwise).
- Custom break-even. At ~$444/year total, the custom stack needs ~0.04% incremental revenue — roughly $770 over a full year. One extra order per fortnight. In every project we have shipped, break-even fell inside week one.
Section 6 — When Adobe Sensei is still the right answer
The three scenarios where Sensei beats the custom stack on operational merit, not just on cost:
- Already on Adobe Commerce. Sensei is included. Marginal cost is zero. Storefront wiring ~16h. Skip the embedding build, use what is bought.
- Over 500K SKUs at 1M+ monthly sessions. Sensei's behavioural collaborative filter at that scale outperforms a vanilla cosine setup. The custom stack can match it but the reranker layer needs more engineering attention.
- Zero in-house engineering. Sensei is "turn it on and watch it work". The custom stack is ~12h dev + nightly cron monitoring. If neither is on the table, Sensei wins by default.
Section 7 — Scope honesty and ship schedule
The custom stack nails "More Like This" by construction. "Customers Also Viewed/Bought" need a co-view/co-purchase matrix from behavioural events — a separate week. "Recommended for You" needs user embeddings — another two weeks. Ship More Like This first, validate, layer the behavioural matrices once the win is proven. Realistic 14-day schedule: Day 1–2 schema + embedding CLI + cron; Day 3 first catalog run + spot-checks; Day 4–5 PDP block + Hyvä template + 50/50 A/B harness; Day 6–13 GA4 tracking on CTR + AOV + conversion; Day 14 promote winner or iterate.
FAQ
Can I run Adobe Sensei on Magento Open Source?
No. Adobe's product page is explicit[1]: Sensei Product Recommendations is Adobe Commerce only. No community port, no Adobe IO Runtime endpoint a non-Commerce merchant can authenticate against. The custom embeddings approach is the realistic path on 2.4.4 — 2.4.9.
Why text-embedding-3-small and not text-embedding-3-large?
At 1,536 dimensions and $0.020 per 1M input tokens, text-embedding-3-small hits the catalog sweet spot[2]. text-embedding-3-large is 3,072 dims at $0.130 per 1M — 6.5x cost for marginal quality that does not show up in CTR on catalogs under 500K SKUs. Upgrade path is one config line.
Do I need a separate Postgres instance for pgvector?
No — pgvector is an extension on any PostgreSQL 15+. If your stack is MySQL-only (Magento default), the cleaner path is OpenSearch k-NN. You already run OpenSearch on 2.4.4 — 2.4.9, so adding a k-NN index is one mapping update.
How does it handle product attribute changes?
The nightly job filters on updated_at > NOW() - INTERVAL '24 hours'. Any SKU whose attributes, description, or category changed in 24h gets re-embedded. The vector store update is idempotent (ON CONFLICT DO UPDATE) and the PDP cache key includes the embedding version, so re-embedding invalidates downstream caches automatically.
What is the GDPR posture compared to Sensei?
The embedding job sends product catalog data to OpenAI. No customer PII leaves the store — embeddings are over the catalog, not over behaviour. Sensei in contrast egresses behavioural clickstream to Adobe Experience Platform, which is a heavier GDPR conversation for EU merchants.
Can I A/B test against Magento native related products?
Yes. Split traffic 50/50 at the PDP block via a deterministic hash of the session ID. Track CTR on the widget, downstream conversion, and AOV of orders that touched the widget. Two weeks at 5,000+ PDP views per arm is enough to read a 3-point CTR uplift with 95% confidence.
Does this work on Hyvä themes?
Yes — the recommendation block is a standard Magento block with a Hyvä-compatible PHTML template (Tailwind grid + Alpine.js swipe carousel). No PWA Studio or React layer required.
How is this different from semantic search?
Infrastructure overlaps — same embedding model, same vector store. Semantic search embeds the user's query at request time. Recommendations embed the current PDP (or session history). One pgvector or OpenSearch k-NN index serves both, so once semantic search exists the marginal cost of recommendations is near zero.
Related reading
- ChatGPT + Magento 2 — four real patterns
- Magento GraphQL custom resolver walkthrough
- Magento 2 development service
Citations
- Adobe Sensei — Adobe Commerce Product Recommendations (business.adobe.com/products/sensei)
- OpenAI text-embedding-3-small / text-embedding-3-large pricing and dimensions (openai.com/embeddings)
- OpenSearch k-NN with HNSW indexing (opensearch.org/docs/knn)
- pgvector — Open-source vector similarity search for Postgres (github.com/pgvector/pgvector)
I scope and ship recommendation stacks on Magento 2.4.4 — 2.4.9 + Hyvä — embedding job, pgvector or OpenSearch k-NN index, PDP block, A/B harness, and a 14-day uplift report. Fixed quote from $499 audit · $2,499 sprint · ~16h @ $25/hr. See hire me.