| Fact | Value | Source |
|---|---|---|
| Active store views | 116 | store table |
| Websites | 6 | store_website table |
| Customer groups | 66 | customer_group table (~3 likely inactive/archived) |
| Search engine | elasticsuite | catalog/search/engine config |
| Magento edition | Adobe Commerce (B2B) 2.4.6-p15 | composer.json |
| Website | Region | Store views | Notes |
|---|---|---|---|
| 1 | Global / ROW | ~67 | English only — Americas, Africa, Asia, Middle East |
| 2 | Europe | ~42 | English + native language views (de_de, fr_fr, es_es, nl_nl, pt_pt, pl_pl) |
| 3 | USA / Mexico | 3 | English + us_es, mx_es, mx_en |
| 4 | Canada | 1 | ca_fr |
| 5 | New Zealand | 1 | nz_en |
| 6 | (TBC) | — | 6th website in DB — likely staging/admin |
Key finding: This is genuinely multi-language, not just multi-currency. German, French, Spanish, Dutch, Portuguese, Polish native-language store views exist. Any search index must handle language-aware tokenisation and relevance per locale.
Coveo is an enterprise AI-powered search platform that operates as a push-API-only service from a Magento integration standpoint — there are no native Magento indexers. Data flows one-way: Magento → Coveo Cloud via the Push/Stream API. The frontend is built separately using either:
<atomic-search-interface>, <atomic-facet>, <atomic-result-list> etc). Uses Shadow DOM for style encapsulation; styled via CSS ::part() pseudo-elements. Framework-agnostic.Authentication: Frontend clients never expose an API key. A short-lived search token is generated server-side (PHP controller) by calling the Coveo Token API, carrying a user identity payload:
{
"userIds": [{"name": "user@email.com", "provider": "Email Security Provider"}],
"userGroups": ["b2b-group-name"]
}
This token gates which indexed content and pricing the session can see — the core mechanism for B2B.
Authentication & B2B Pricing — dictionaryFieldContext: This is the key mechanism for PE's 66-group B2B pricing. A dictionary field (e.g. @price) stores a key→value map on every indexed product, where each key is a customer group identifier. The search token carries a dictionaryFieldContext parameter that locks the session to one key:
{
"userIds": [{"name": "user@email.com", "provider": "Email Security Provider"}],
"userGroups": ["b2b-group-name"],
"dictionaryFieldContext": { "price": "group_42" }
}
At query time, any reference to @price in a facet or sort resolves only the group_42 value for that session. No frontend changes needed per group — the token does all the work. Ashley confirmed in the call that the demo showed an array of group→value price pairs returned in the result payload. This is a first-class Coveo feature, not a workaround.
Delivery Assurance Programme (confirmed in Coveo call): Included at no additional cost with Commerce contracts. Comprises: - Kickoff call + 10 flexible workshops covering: technical readiness, source connectors, catalog architecture, UI dev (search box, query pipeline, ML, recommendations), go-live prep - Implementation review — Coveo validate backend configuration and UI functionality before go-live - 24/7 Technical Support + Customer Success team for training + self-learning resources - A named contact from Professional Services (Ashley + Dario) throughout
This directly addresses the "enterprise overkill" concern — Coveo are actively guiding the implementation, not leaving PE to figure it out alone.
UI Library recommendation (from call): Ashley specifically recommended Coveo Headless over Atomic for Magento/bespoke B2B implementations, citing greater flexibility and control, particularly for custom pricing blocks. This aligns with our Alpine.js + Headless recommendation.
AI/Agent features: Coveo has Generative Answering (RGA) — a RAG-based LLM layer exposed via Atomic's <atomic-generated-answer> component or the Headless GeneratedAnswer controller. Genuinely LLM-backed (not scripted), pulling context from indexed documents. Also supports AI merchandising, relevance tuning, and recommendations. Their "Quantic" library is the Salesforce LWC variant — not relevant here. AI agent priority not confirmed by PE yet — deferred to later in the process.
Product badging (confirmed in call): Coveo has a native out-of-the-box badging feature that allows non-technical users (PE's team) to manage promotional labels without dev involvement. Contact Myles Peyton at Coveo for a demo.
Algolia is a hosted search engine with an official, actively maintained Magento 2 module that: - Installs native Magento indexers (product, category, CMS) - Overrides frontend search (InstantSearch.js, autocomplete library) - Provides admin configuration UI under Stores > Algolia - Handles multi-store via per-store-view index name suffixes - Supports merchandising rules in the Algolia dashboard
The module is opinionated and ships its own JS bundles, LESS/CSS, and templates — suitable for standard implementations with theme-level overrides. Alternatively, Algolia can be used headless via their API clients (ignoring the M2 frontend entirely), which gives the same level of UI flexibility as Coveo's Headless SDK approach. Confirmed by Algolia in their vendor Q&A (A10). Version upgrades only affect the indexing layer in the headless approach, not the frontend.
AI features: Algolia NeuralSearch is available (semantic vector search). Their "AI Assistant" is intent-classification based (scripted conversation trees triggering product recommendations by matched intent) — not a true LLM.
Commercial context: Ayko has an existing Algolia relationship (possibly referral/commission basis — Will to confirm). However, no new PE project has used Algolia for several years. Coveo is a new contact — Penn-Elcom found them independently and have had an introductory pitch call with Professional Services. No contract signed for either.
Context: Penn-Elcom's concern is that Coveo is an enterprise platform pitched at £6B revenue businesses and may be overkill or overpriced for their scale. Their read is that Coveo means more dev effort but a better end result. This section addresses the commercial picture honestly.
| Component | Detail | Cost (GBP) |
|---|---|---|
| Annual subscription | 100k QPM, Personalization As-You-Go, Business-Aware Product Ranking, Enterprise | £39,631/year |
| 3-year subscription total | Fixed term 30 Jun 2026 → 29 Jun 2029 | £118,893 |
| Onboarding / Delivery Assurance | Included in contract | ✅ No extra cost |
| Sandbox (non-production org) | Included | ✅ Included |
| EU hosting | Included | ✅ Included |
| Generative Answering (RGA) | Not confirmed as included — needs clarification | TBC |
Renewal: Auto-renews at Coveo's applicable list price at the time (not a fixed escalator — could go up or down).
Contacts: Myles Peyton (AE, +44 7880054552), Robert Platt (billing), Andrew Martin (admin).
Delivery Assurance: Confirmed included. Provides structured workshops, schema design review, go-live validation, 24/7 enterprise support with named contacts.
Quoted plan: Elevate for Ecommerce (Algolia NeuralSearch) — effectively their top commercial ecommerce tier.
| Component | Detail | Annual cost (GBP) |
|---|---|---|
| Subscription (Year 1) | 4.92M search requests, 240k records, 1.4M recommend requests | £25,182 |
| Subscription (Year 2) | Auto-renews at +7% | £26,945 |
| Subscription (Year 3) | +7% again | £28,831 |
| 3-year subscription total | £80,958 | |
| Onboarding (one-time) | Professional services — not optional | £4,698 |
| 3-year total committed | ~£85,656 |
Conversion: €1 = £0.8541 (2026-07-07 Frankfurter API)
What's included: - NeuralSearch (AI-powered relevance) ✅ - Algolia Recommend (1.4M requests/year) ✅ - Analytics Extended Retention ✅ - Core Foundation ✅ - Onboarding (€5,500 one-time) ✅
Overage rates (expensive — billed monthly in arrears): | Unit | Overage rate | |------|--------------| | Search requests | £1.67 per 1,000/month | | Records | £4.10 per 1,000/month | | Recommend requests | £0.51 per 1,000/month |
⚠️ Quote expiry: The quote stipulates Algolia can reject it if not signed by 30 June 2026. That date has passed. A revised quote will be needed — pricing may differ.
⚠️ 7% annual escalator: Fees increase automatically by 7% at each renewal. Unused search/record units do not roll over.
The quote includes a 240,000 record maximum. The figure almost certainly maps to:
6 websites × 7,800 products × ~5 (1 main index + 4 sort replicas) = ~234,000 records ≈ 240,000 cap
This means Algolia have scoped PE as per-website indexing with sort replicas — a reasonable standard assumption. The risk is what they haven't accounted for:
| Scenario | Records | Within 240k cap? |
|---|---|---|
| 6 website indexes, no replicas | ~46,800 | ✅ Comfortably |
| 6 website indexes + 4 sort replicas each | ~234,000 | ✅ Just inside (likely what Algolia quoted) |
| Above + 9 language-specific indexes (no replicas) | ~304,200 | ❌ Over cap |
| Above + replicas on language indexes too | ~500,000+ | ❌ Well over cap |
The language index gap is the real risk. PE have 9 native-language store views (de, fr, es, pt, pl, nl, mx_es, us_es, ca_fr) confirmed active with full translations. Algolia's M2 module creates language-specific indexes by default for correct tokenisation. If Algolia's PS team haven't factored these in, the 240k cap is underscoped.
Overage rate: £4.10 per 1,000 records/month. At 300k records over cap, that's ~£1,230/month (£14,760/year) — meaningful but not catastrophic. At full language+replica expansion it could be higher.
Question 20 (below): confirm how Algolia have scoped the record count and whether language-specific indexes are included.
Key hard limit confirmed in PE call (transcript 00:21:57):
Will: "I think what they said is that their limitation for B2B pricing is 20 prices for a product which some products might be under this but obviously in the future that's going to change."
Algolia's proposed workaround (as quoted in the call): Rather than indexing prices, lazy-load them from Magento at search-result-render time via a custom API endpoint. Coveo's pricing data doesn't sit in Algolia — it's fetched dynamically on demand. - Custom endpoint estimate: ~30 hours. - UX implication: Price shows with a loading spinner or is blurred/deferred until the Magento API responds. Will acknowledged "it's hard to know until we've actually done the work" how fast this will be. - Future maintenance: Once built, growing price lists don't require re-indexing. But Magento performance becomes a dependency for PLP price display speed. - This is not an Algolia feature — it is bespoke Ayko dev work to work around Algolia's B2B pricing limitation. It is mandatory at all tiers — without it, Algolia cannot show correct B2B prices. - Important scope note from PESLA-1599: The estimate covers the lazy-loading integration layer only. It explicitly excludes: Algolia module installation/configuration, index setup and product sync, search results template redesign, ElasticSuite migration, and multi-store regression testing. A further 4h investigation is recommended before full commitment to validate SharedCatalog pricing model compatibility with the Algolia module hook points.
Both quotes now confirmed. The actual subscription delta is £33,237.
| Cost Component | Algolia | Coveo |
|---|---|---|
| Annual subscription (Year 1) | £25,182 (Q-55286) | £39,631 (OF.V1.DD-24-6-26) |
| Annual subscription (Year 2) | £26,945 (+7% fixed escalator) | £39,631 (fixed 3yr term) |
| Annual subscription (Year 3) | £28,831 (+7% fixed escalator) | £39,631 (fixed 3yr term) |
| 3-year subscription | £80,958 | £118,893 |
| Onboarding / PS (one-time) | £4,698 | ✅ Included in contract |
| 3-year committed total | £85,656 | £118,893 |
| Subscription delta (3yr) | — | Coveo £33,237 more |
| Year 1 implementation (Tier 1) | ~£8–10k | ~£14–20k |
| PESLA-1599 (mandatory, all tiers) | +£3,800 | ❌ Not required |
| Ongoing maintenance overhead | ~£2–4k/year | ~£0.5–1k/year |
| 3-year TCO (Tier 1 example) | ~£102–108k | ~£138–146k |
| Record overage risk | ⚠️ Language indexes may breach 240k cap | ❌ No record limit |
| Expansion headroom (Thailand, China) | ⚠️ Adds ~2 language indexes + records (see §2.3a) | ✅ Add 2 sources, no extra cost within QPM |
| 3-year TCO delta | Algolia ~£30–40k cheaper | Higher subscription, lower operational risk |
The full TCO gap is wider once implementation, PESLA-1599, and maintenance are included, but Algolia remains the lower-cost platform if record counts stay within the cap.
New information (2026-07-08): PE are planning two new stores next year — Thailand and China.
Coveo impact: Add 2 new sources (or grouped under existing websites if architecture allows). 100k QPM cap unchanged — verify current search volume to confirm headroom. Zero additional subscription cost during the 3-year term.
Algolia impact — significant:
| Item | Notes |
|---|---|
Thai language index (th_th) |
Requires dedicated index for correct Thai tokenisation. Algolia handles Thai but requires a separate index per locale. |
Chinese language index (zh_cn) |
Simplified Chinese requires separate index. Significantly different tokenisation — cannot share a Western-language index. |
| Record impact | +2 language indexes × 7,800 products = +15,600 base records. With replicas: +62,400–78,000. Pushes closer to or through the 240k cap depending on current language index count. |
| Module configuration | 2 new store views to configure in Algolia admin. Additional regression test scope. |
The 240k record cap was quoted before Thailand and China were on the roadmap. Even if the current scoping is within the cap today, these stores could push PE into overage territory at renewal. This must be raised with Algolia — added to Q20.
Important framing: Most Algolia limitations are operational concerns, not implementation cost items. The table below explicitly separates the two. Only items in the first section influence the quoted estimate.
B2B pricing at 66 groups [Mandatory — PESLA-1599, 30h 45m quoted]
Algolia has no dictionaryFieldContext equivalent. The chosen workaround is lazy-loading prices from a custom Magento REST endpoint rather than indexing them. This is confirmed as the approach via PESLA-1599 (Dean Morgan, 2026-07-03). Without this work, Algolia cannot show correct B2B prices. Cost is fixed regardless of tier.
Contrast with Coveo: A single @price dictionary field, one token parameter, all 66 groups served from a single index. No additional dev work at any tier.
Module upgrade regression testing [Module approach only — not applicable to headless/API approach]
If using the M2 module frontend, Algolia module updates may affect bespoke theme overrides. With the headless/API approach, module updates only touch the indexing layer — frontend components are Ayko-owned and unaffected by module releases. This is therefore only a relevant cost consideration if the Basic (module) track is chosen.
| Limitation | Notes | Assessment |
|---|---|---|
| 116 index management | Merchandising rules, synonyms, relevance tuning are per-index. Bulk tooling pending Algolia response. | Doesn't change implementation cost — PE's problem to manage |
| SKU infix/partial search | Current ElasticSuite ngram search is poor. Both platforms need this configured. Algolia requires API-level config; may not be in module UI. | Not a regression — current search is poor anyway |
| No native badge rendering | Amasty continues in search context. New badge types need dev each time vs Coveo self-serve. | PE operational benefit only; Coveo still needs PDP badge dev |
| AI agent (scripted vs LLM) | Algolia's AI Assistant is intent classification. Coveo RGA is genuine LLM. | Tier 3/future concern only. Doesn't change implementation cost |
| Secured API Key field visibility | Keys restrict which records appear, not field values. Minor risk with lazy-load approach as prices aren't indexed. | Massive edge case; doesn't change implementation cost |
| No Delivery Assurance equivalent | Coveo's workshops are valuable because Coveo needs more figuring out from scratch. Algolia's module removes that ambiguity. | False equivalency — Algolia doesn't need the same level of support |
Updated 2026-07-10: Algolia confirmed via vendor Q&A (A10) that a fully headless/API approach is a first-class option — using the extension purely for indexing and building the frontend with Algolia's JS libraries or API clients directly. This removes module template ownership as a constraint.
Two distinct Algolia implementation paths exist:
Module approach (Algolia Basic):
Use the M2 module's InstantSearch.js frontend with theme-level overrides. Module owns product card templates — bespoke elements (enquiry CTAs, custom price display) are retrofitted via theme overrides. Faster initial build, less upfront dev, but customisation depth is constrained by what the module exposes. Suitable if PE's search ambitions are limited.
Headless/API approach (Algolia High):
Use the extension for indexing only. Build all frontend components from scratch with Algolia's JS API clients + Alpine.js — same architecture as the Coveo approach. Full UI control, no module upgrade regression risk, same build effort as Coveo Tier 1–2. B2B lazy-pricing (PESLA-1599) remains mandatory regardless of approach.
Ayko\NonTransactionalProductsCodebase confirmed (2026-07-08): The toolbar toggle is an existing bespoke Ayko module, not a Magento-native or ElasticSuite feature. It must be migrated to whichever search platform is chosen.
How it currently works:
The non_transactional boolean product attribute marks enquiry-only products (value 1). The toolbar toggle (Full Catalogue / Buy Online) controls whether these products are visible.
| Layer | Implementation |
|---|---|
| UI | toggle.phtml — rendered in toolbar, fires AJAX POST to SwitchAction controller |
| State | ContextSwitcher observer stores toggle state in DataPersistor + Magento HttpContext (FPC variation key) |
| Search filter | Model/Elasticsuite/.../NonTransactional implements ElasticSuite's FilterInterface — applies bool query excluding non_transactional=1 products when "Buy Online" is active |
| Layered nav fix | RemoveFilterFromCollection plugin strips non_transactional from ES collection filters to prevent it breaking layered navigation |
| PDP | ResultPage plugin adds layout handle catalog_product_view_type_available_in_store on enquiry-only PDPs (shows enquiry form instead of add-to-cart) |
What needs to change when ElasticSuite is replaced:
Model/Elasticsuite/... filter class — dead code. Retire.RemoveFilterFromCollection — dead code (ES collection specific). Retire.ContextSwitcher observer + HttpContext + SwitchAction controller — may survive but need rewiring to the new search backend.Algolia migration:
Index non_transactional attribute. Convert the toggle from a POST/server-session mechanism to a JS-driven filter. Apply as an Algolia filter string (NOT non_transactional:true). The current HttpContext/FPC state model doesn't translate cleanly to Algolia's client-side rendering — you end up with a hybrid server+client toggle state, harder to reason about and test. The module's own filter architecture needs extending to accept this parameter, which means working against the module's assumptions.
Coveo migration:
Index non_transactional as a field. Build the toggle as an Alpine.js StaticFilter or Tab controller — Coveo Headless's TabManager is designed exactly for toggling between views of the same result set via a query condition:
// Alpine component — state managed by Headless URL manager
{
toggleBuyOnline() {
engine.dispatch(toggleSelectStaticFilterValue({
id: 'catalogue-mode',
value: { expression: 'NOT @non_transactional==1' }
}))
}
}
State is managed by the Headless URL manager — deep-linkable, bookmarkable, back-button safe. ES-specific classes are retired cleanly. No hybrid server/client state to maintain. The enquiry form CTA on PDPs continues via the existing ResultPage layout handle mechanism, which is Magento-native and platform-agnostic.
Short answer: probably not, but it depends on the QPM figure and contract minimum.
The "£6B revenue" framing is Coveo's marketing. Their Commerce product is actively sold to mid-market retailers. The meaningful question is not revenue size — it's search query volume. PE is a B2B specialist manufacturer with a defined customer base (5 companies, 66 groups). Their search query volume is almost certainly modest compared to a consumer B2C retailer at comparable GMV. If Coveo's QPM pricing is based on volume, PE could be in a very affordable tier.
The risk is contract minimums — if Coveo requires a £40k+/year minimum regardless of volume, that changes the conversation. This is the single most important commercial question to get answered before recommending Coveo.
What PE should push Coveo for: A query volume estimate based on their actual traffic data, and a per-tier price breakdown. If Coveo can't or won't provide transparent indicative pricing, that itself is a commercial red flag.
| Scenario | Recommendation |
|---|---|
| Coveo contract minimum is within PE's budget | Coveo — technical fit is clearly superior for their B2B complexity |
| Coveo contract minimum is prohibitive | Algolia Premium with architectural B2B mitigation — accept the limitations, design around them, but be explicit with PE about what they're trading off |
| Neither contract is palatable | ElasticSuite upgrade path — invest in upgrading the existing stack (newer ES/Opensearch, improved front end) rather than a third-party SaaS dependency |
PESLA-1599 (30h 45m) is mandatory for Algolia at all tiers and must be added to every Algolia estimate. It is not in Coveo's scope at all. At Tier 2, this alone narrows the gap between Algolia and Coveo to near-zero before any other work is considered. At Tier 3, with module fighting and the B2B overhead, Algolia likely costs more in dev than Coveo.
The site runs Smile ElasticSuite open-source (smile/elasticsuite: ^2.11, smile/module-elasticsuite-shared-catalog: ~2.11.0) — confirmed as the community (free) edition, no enterprise license. Also installed: vortex/indexer-statistics-smile-elasticsuite (third-party indexer stats module), ayko/elasticsearch-index-cleanup (custom cleanup cron), ayko/merchandisingsmile (custom merchandising rules). All ElasticSuite-specific dependencies can be retired post-migration once the fallback decision is finalised.
| Module | Purpose | Migration Implication |
|---|---|---|
Ayko_SearchAutocomplete |
Injects SKU into ElasticSuite autocomplete (AttributeConfig DI arg) so SKU appears in the typeahead dropdown |
Replace entirely — Coveo/Algolia autocomplete is built from scratch. SKU must be a searchable field in the new index. |
Ayko_ElasticsuiteSearchBySku |
Adds ngram_sku edge-ngram analyzer to ElasticSuite, enabling partial SKU search (e.g. searching "4U" matches "rack-4U-12") |
Critical requirement to replicate — Coveo: configure field tokenisation in Push API mapping. Algolia: searchableAttributes with ngram-style settings. |
Ayko_SmileElasticsuiteIndexDeduplication |
Prevents duplicate ES index creation per store dimension | Retire post-migration — Coveo/Algolia manage their own index structure |
Ayko_ElasticsuiteStatusAttributeFix |
Fixes product status filtering in ES collections | Retire post-migration — irrelevant to external search platforms |
Ayko_CatalogRuleOptimisation |
See §3.3 | See §3.3 |
This module contains two plugins:
AddCatalogRulePriceToProductCollection — hooks Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection::afterGetProductCollection() to call CollectionProcessorFactory::addPriceData(). This injects catalog price rule discounts into the ElasticSuite product grid so discounted prices display on PLPs. It is ElasticSuite-specific and will become inert when ElasticSuite is removed.
FinalPricePlugin — hooks ProcessFrontFinalPriceObserver::beforeExecute() to populate RulePricesStorage with the catalog rule price from the product object if present, keyed by date|website|customerGroup|product. This affects final price resolution on PDPs.
Important distinction: Penn confirmed no active catalog price rules — they tried to get them working but couldn't, and now rely solely on cart price rules at checkout. This means: -
Ayko_CatalogRuleOptimisationis effectively dead code — can be flagged for removal during migration - The catalog rule price issue does not affect search result prices (no active rules to push) - Cart price rules (checkout discounts) are handled entirely within Magento's quote/order system and are irrelevant to the search integration
Ayko_NonTransactionalProducts module confirmed — this handles enquiry-only products (no add-to-cart). In search results:
- Push a boolean field to index: is_non_transactional: true/false
- Product card component conditionally renders "Enquire Now" vs "Add to Cart"
- Existing modal form logic can be retained — just needs the trigger wired up to the new card component
| Module | Purpose | Implication |
|---|---|---|
Ayko_SharedCatalog |
Extends Magento_SharedCatalog with custom TierPrice and GroupPrice indexer plugins; AddFallbackGroupID plugin |
Prices pushed to Coveo must carry group-keyed price fields per customer group |
Ayko_SharedCatalogueAssignment |
Console tool for bulk shared catalog product assignment | Informs sync scope — products can differ per catalog |
Ayko_CompanyLocale |
Locale settings per company | Relevant for language-scoped search tokens |
Ayko_CompanyExternalCustomerId |
Maps company accounts to SageX3 ERP IDs | May affect B2B identity in search token (ERP group ≠ Magento group) |
Ayko_CompanyExtensionAttribute |
Custom attributes on company entities | May need fields in the index |
Ayko_DisableAutoGroup |
Disables automatic customer group assignment | Indicates group assignment is manually managed — important for token identity |
magento/extension-b2b: ^1.4 |
Core B2B (shared catalogs, company accounts, quotes) | Full B2B stack active |
| Module | Notes |
|---|---|
Ayko_Trustpilot |
Custom wrapper around trustpilot/module-reviews ^2.6 — star ratings on product pages |
amasty/module-product-labels-subscription-pack |
Condition-based product label badges |
ayko/merchandisingsmile |
Custom ElasticSuite merchandising rules |
ayko/module-indexer-statistics-merchandising |
ES indexer stats |
ayko/elasticsearch-index-cleanup |
ES index cleanup cron |
Ayko_GeoIpRedirect |
GeoIP-based store view redirect |
Ayko_InternationalUrlRewrites |
International URL structure |
Ayko_PriceListDownload |
Downloadable price lists |
Ayko_EuNavigation / Ayko_Menu |
Custom nav/menu |
Ayko_Msrp |
MSRP display logic |
Ayko_CountrySelector |
Frontend country/store switcher |
| Capability | Coveo | Algolia |
|---|---|---|
| Per-customer-group pricing in index | ✅ Custom fields — you define schema | ⚠️ Supported but per-attribute config required |
| Search token per customer/group | ✅ First-class — userIds + userGroups in token |
❌ No token model — API key only; B2B needs separate indexes or runtime filter injection |
| Multi-store / multi-language | ✅ Three source options: 116 per-store-view, 6 per-website (Tracking ID scoping), or 1 multi-market (PS commitment). All work without frontend changes. | ✅ Per-store-view index (auto via M2 module) |
| Native language search (tokenisation) | ✅ Language set per source — Coveo handles it | ✅ Index-level language settings |
| Shared catalog scope | You define what goes in the push | M2 module handles automatically |
| B2B catalog visibility per company | userGroups in search token — clean, single index |
Separate index per group or complex runtime filters |
At 66 customer groups × 116 store views: Coveo's single-index-with-token-gating approach is far cleaner than Algolia's index-per-group model (which would imply up to 66 × 6 = 396 potential indexes). Even with Algolia's filtering approach, injecting 66 different price group filters correctly per session is fragile.
| Aspect | Coveo | Algolia |
|---|---|---|
| Frontend architecture | 100% custom UI | Module owns ~80%, you customise the rest |
| Product card | Fully custom Alpine/Headless | Override InstantSearch templates |
| Mini-search (typeahead) | Build from scratch | Override Algolia autocomplete widgets |
| PLP facets | Headless controllers or Atomic components | Override Algolia facet widgets |
| B2B price display | Fully custom — render whatever token returns | JS hooks into Algolia module |
| Enquiry-only products | Custom conditional render logic | Algolia event hook + custom template |
| Product badges/labels | Coveo Atomic field-conditional rendering — native | Amasty module or custom template |
| AI chat agent | Coveo RGA — true LLM/RAG | Algolia AI Assistant — scripted intent classification |
| Future extensibility | API is the only limit | Limited by Algolia M2 module architecture |
GitHub: Coveo-Turbo/magento-integration
Feature set (from README and repo): - Multi-store: ✅ per-store-view configuration - B2B shared catalog: ✅ full + delta sync with separate batch sizes per catalog - Push/Stream/File Container APIs: ✅ all three integrated - Delta sync: ✅ via Magento observers (product save/delete) - Product variants (configurable, bundle, grouped): ✅ - Category hierarchy: ✅
Code quality issues: - 2 commits total, single branch, minimal tag history — immature release cadence - No return types on methods, no property promotion (confirmed in your review) - No visible unit or integration tests - PHP 97.7%, HTML 2.3% - Would not pass Ayko's internal code standards
Coveo's own recommendation (from call): Ashley specifically called out the Coveo Turbo integration as an accelerator for Magento implementations and endorsed using it as the backend data pump. This adds credibility to using it as a base — Coveo's PS team are familiar with it.
Source architecture — three confirmed options (from Coveo written Q&A):
| Option | Sources | Connector changes | Status |
|---|---|---|---|
| A — 116 per-store-view sources | 116 | None | ✅ Works today |
| B — 6 per-website sources | 6 | None | ✅ Works today |
| C — Multi-market single source | 1 | Connector enhancement needed | ⚠️ PS commitment, not yet built |
Option B detail (from Coveo Q&A): Per-website sources are scoped to the correct store view using a Tracking ID + Storefront Association — a mapping that links the Tracking ID with a language/country/currency combination to a Catalogue configuration. Each property gets a separate query pipeline for search, listings, and recommendations. Filter rules for the correct products are applied automatically from the Catalogue config. No connector changes required.
Option C detail: Multi-market catalogue sources introduce "catalogue views" — one product record with localised data per view, or an attribute defining which catalogue(s) a product belongs to. The Turbo connector would need minimal customisation. Coveo PS commit to making these enhancements if PE proceed.
⚠️ Option C connector enhancements are not yet built — this is a PS commitment. Options A and B work today. Option B (6 sources) is likely the pragmatic starting architecture — significantly lower admin overhead than 116 sources, no additional connector work.
📌 Pricing implication: Source count does not affect the subscription cost. The 100k QPM allowance is shared across all sources regardless of architecture chosen.
Decision options:
| Option | Effort | Notes |
|---|---|---|
| ~~Refactor Turbo module to Ayko standards~~ | ~~3–4 days~~ | Off table — Will confirmed project will not be signed off with refactor scope included |
| Use as-is with targeted patches | 1–1.5 days | Accepted approach — patch specific issues (missing return types where they cause errors, critical DI issues) without full standards lift |
| Build clean from scratch | 5–7 days | Full control, but harder to justify commercially given Coveo PS endorse the module |
Recommendation: Use Turbo as-is with minimal targeted patches. Accept the code quality limitations as managed tech debt. Scope any patches to what is strictly necessary for the integration to function correctly at PE's scale. Raise any gaps found during the Delivery Assurance workshop review.
Ayko_Trustpilot wraps the Trustpilot module. Rating badges on product cards in search results:
Recommend Option B with a lightweight caching layer (Redis-backed Magento endpoint) to avoid Trustpilot API rate limits on high-traffic searches.
amasty/module-product-labels-subscription-pack handles condition-based product labels (NEW, SALE, CLEARANCE etc) site-wide. In the search context, Coveo Atomic provides atomic-field-condition — a result template component that conditionally renders content based on an indexed field value. This means:
badge_label field (or multiple boolean fields: is_new, is_sale, is_clearance) to the Coveo index at sync timeThis does not retire the Amasty module site-wide (it still handles PDP, category pages, etc.) but removes the need for label hydration in the search/PLP context.
Ayko_NonTransactionalProducts already tracks which products are enquiry-only. Push is_non_transactional: true/false to the index. Product card renders conditionally. Modal form remains as existing Magento component, triggered from the new card.
Penn confirmed they use cart price rules (checkout/quote), not catalog price rules, for promotions. The CatalogRuleOptimisation module is an attempt to fix a separate pre-existing issue where catalog-level price rules (rules applied to PLP/PDP prices before checkout) weren't working.
This is a separate discovery spike — no search platform will resolve it. The search platform will display whatever price is pushed to the index. If catalog rules are later fixed in Magento, the push sync would need to resolve final prices inclusive of those rules.
The DB scan confirmed native-language store views: de_de, fr_fr, es_es, nl_nl, pt_pt, pl_pl, mx_es, us_es, ca_fr. This means:
Ayko_GeoIpRedirect routes visitors to country store views. The Coveo search token must be generated after store view resolution — it should carry the active store view scope so results are filtered to the correct regional catalog, currency, and language. This is straightforward but must be explicitly built into the token generation controller.
Resilience concern: Both Coveo and Algolia are external APIs. If either has an outage, the search-dependent parts of the site (mini-search, PLPs, search results) go down. Manual switching is not acceptable.
ElasticSuite is currently self-hosted (on the same infrastructure). Coveo and Algolia are SaaS platforms with their own SLAs. Both claim high availability (Coveo: 99.9% SLA, Algolia: 99.99% SLA), but outages do occur.
| Strategy | Complexity | User Experience |
|---|---|---|
| Silent fallback to Magento/ES native search | High | Transparent — user sees results, quality degrades |
| Fallback to cached last-known results | Medium | Acceptable for common queries, fails for long-tail |
| Graceful error state ("Search temporarily unavailable, browse categories") | Low | Honest but poor UX |
| Health-check-gated toggle in session | Medium | Switch to ES if Coveo unreachable on token fetch |
On page load, the search token endpoint (PHP controller) checks Coveo availability. If the token request fails or times out:
1. Controller sets a session/cookie flag: search_provider=fallback
2. Frontend reads the flag and renders the native Magento/ElasticSuite search block instead of the Coveo UI
3. When Coveo recovers, subsequent page loads restore the Coveo token and clear the flag
Key requirement: ElasticSuite must be retained (not removed) even after Coveo goes live. It becomes the fallback search engine. The custom ES modules (ElasticsuiteSearchBySku etc.) should also be retained for the fallback to work correctly.
⚠️ Architectural implication: This adds meaningful scope to all tiers. The site effectively needs to maintain two parallel search stacks. Keeping ES alive is straightforward (no new code), but the health-check gateway and conditional UI rendering is additional work. Estimate this at +2–3 days across any tier.
| Coveo | Algolia | |
|---|---|---|
| Stated SLA | 99.9% | 99.99% |
| Circuit breaker / fallback tooling | Manual (we build it) | Manual (we build it) |
| Status page | status.coveo.com | status.algolia.com |
Algolia's SLA is stronger on paper. In practice, both require the same fallback architecture at PE's scale.
Confirmed: Alpine.js + Coveo Headless SDK
Alpine is already used in Ayko's Hyvä builds and Shopify themes — the team knows it, the patterns are established. It maps naturally to Headless controllers via x-data reactive state. No build pipeline changes needed in the Magento theme (Alpine loads from CDN or bundled via theme). For the Coveo integration:
// Example Alpine + Headless pattern
Alpine.data('coveoSearch', () => ({
engine: null,
searchBox: null,
query: '',
suggestions: [],
init() {
this.engine = buildSearchEngine({ configuration: { ... } });
this.searchBox = buildSearchBox(this.engine);
this.searchBox.subscribe(() => {
this.suggestions = this.searchBox.state.suggestions;
});
},
updateQuery(value) {
this.searchBox.updateText(value);
this.searchBox.showSuggestions();
}
}));
For the AI chat agent (Tier 3), the Headless GeneratedAnswer controller wires into the same Alpine component pattern — no additional framework needed.
| Option | Verdict |
|---|---|
| Alpine.js + Coveo Headless | ✅ Chosen — team familiarity, lightweight, Hyvä-aligned |
| React + Coveo Headless | Overkill for this scope; consider if PE ever goes headless frontend |
| Coveo Atomic Web Components | Usable but Shadow DOM limits deep custom styling |
| Vue 3 + Coveo Headless | Viable but no existing team patterns |
⚠️ Ballpark figures only — not confirmed quotes. Designs must be provided and signed off before Tier 2 or Tier 3 can begin. All tiers assume: Coveo platform access in place, backend module in place, no major blockers from Magento infrastructure. Add +2–3 days to any tier for the fallback/resilience architecture (§5.3).
Goal: Replace ElasticSuite frontend with Coveo search. Same layout/UX as today but AJAX-driven, no redesign. Autocomplete replaces existing. PLP replaces layered nav with Coveo-powered filters. B2B pricing via search token. Fallback to ES if Coveo unreachable.
| Work Item | Estimate |
|---|---|
| Backend module — Coveo-Turbo as-is + targeted patches | 1–1.5 days |
| Search token endpoint (session-aware, store-scoped, B2B group identity) | 1–2 days |
| Fallback health-check gateway + conditional UI flag | 1–2 days |
| Mini-search autocomplete (typeahead, products + categories, SKU support) | 2–3 days |
| Search results page (grid, basic facets, sort) | 3–4 days |
| PLP override (category pages via Coveo, basic checkbox filters) | 3–4 days |
| B2B price rendering (token-gated, group-specific price field) | 1–2 days |
| Multi-store / multi-language source config (116 store views → Coveo sources) | 2–3 days |
| Non-transactional product CTA (conditional render) | 0.5 days |
| QA + cross-browser + multi-store smoke test | 2–3 days |
| Total | ~19–27 days |
| Indicative range | ~£14k–£20k |
Goal: Tier 1 + enriched filter experience equivalent to a well-configured ElasticSuite setup. Price slider, brand/attribute multi-select, category tree, result count, term highlighting, Trustpilot ratings, enquiry modal, product badges.
| Additional Work | Adds to Tier 1 |
|---|---|
Price range slider (Alpine + Coveo PriceRangeFacet controller) |
+1–2 days |
| Brand / attribute multi-select facet panel | +1–2 days |
| Category tree hierarchical facet | +1–2 days |
| Result count, items-per-page, pagination | +0.5 days |
| Term/keyword highlighting in results | +0.5 days |
| Enquiry-only modal integration with new product card | +1 day |
| Trustpilot async hydration (skeleton state, cached Magento endpoint) | +1–2 days |
| Coveo field-conditional badge rendering (replaces Amasty in search context) | +0.5–1 day |
| Search results page enrichment (image, description snippet, richer layout) | +1 day |
| Extended multi-language QA (key language store views) | +1–2 days |
| Adds | +9–14 days |
| Combined Total | ~28–41 days |
| Indicative range | ~£21k–£31k |
⚠️ Requires designs signed off before starting. UI complexity significantly affects this estimate.
Goal: Tier 2 + full-screen Doofinder-style mini-search overlay, Coveo Generative Answering chat agent, fully custom product card components, visual merchandising, analytics events, dynamic recommendations, mobile-optimised. Premium UX end-to-end.
| Additional Work | Adds to Tier 2 |
|---|---|
| Full-screen mini-search overlay (animated panel, keyboard nav, recent searches, trending terms) | +3–5 days |
Coveo GenAI chat agent (Headless GeneratedAnswer controller, custom Alpine chat UI) |
+3–5 days |
| Fully custom product card component (Alpine, handles all product types, B2B price, badge, enquiry) | +2–3 days |
| Visual merchandising integration (Coveo merchandising rules, promoted products) | +1–2 days |
| Analytics event wiring (click, add-to-cart, search pipeline, Coveo usage analytics) | +1–2 days |
Dynamic recommendations (RecommendationList on PLP / search results) |
+2–3 days |
| Catalog rule price discovery spike (understand and scope resolution) | ~~+2–4 days~~ removed — no active catalog rules confirmed |
| Performance / LCP optimisation (lazy hydration, skeleton states, bundle sizing) | +1–2 days |
| Mobile UX polish (touch-optimised filter drawer, responsive grid) | +1–2 days |
| Adds | +16–28 days |
| Combined Total | ~44–69 days |
| Indicative range | ~£33k–£52k |
⚠️ Requires designs signed off before starting. AI agent scope (scripted vs full GenAI) must be confirmed — this estimate assumes Coveo RGA (full LLM) rather than a rules-based chatbot. If PE decide a scripted agent is sufficient, save ~2–3 days.
Estimating principle (Will Brammer, 2026-07-08): Algolia estimates should reflect what PE actually needs — not feature parity with Coveo. If Algolia doesn't natively have something Coveo has, that doesn't automatically add scope to the Algolia estimate.
Updated 2026-07-10: Algolia now structured as two tracks following vendor confirmation of the headless/API approach (A10).
Algolia Basic — module-based, line-item breakdown:
| Work item | Estimate |
|---|---|
| PESLA-1599 — B2B lazy-load pricing, BE + FE (mandatory) | ~4 days |
| Theme-level product card overrides (enquiry CTA, Trustpilot slot, B2B price placeholder) | 1–1.5 days |
| Non-transactional product CTA | 0.5 days |
| Fallback architecture (ES health-check gateway) | 2–3 days |
| Multi-store config verification (116 store views, API keys) | 0.5–1 day |
| QA + cross-store smoke test (pricing accuracy, 3+ customer groups) | 2–3 days |
| Total | ~10–13 days |
Algolia High — headless/API, Alpine.js, full custom build:
| Work item | Estimate |
|---|---|
| PESLA-1599 — B2B lazy-load pricing, BE only | ~2 days |
| Search token / API key management (per-session, store-scoped) | 1–2 days |
| Fallback architecture (ES health-check gateway) | 2–3 days |
| Mini-search autocomplete (Algolia Autocomplete.js, custom Alpine component) | 2–3 days |
| Search results page (grid, facets, sort — Algolia InstantSearch headless) | 3–4 days |
| PLP override (category pages, Algolia-driven filters) | 3–4 days |
| B2B price lazy-load FE (skeleton state, async price injection) | 2 days |
| Multi-store config verification (116 store views, API keys) | 0.5–1 day |
| Non-transactional product CTA | 0.5 days |
| QA + cross-store smoke test | 2–3 days |
| Total | ~18–25 days |
| Algolia Basic | Algolia High | Coveo Tier 1 | Coveo Tier 2 | |
|---|---|---|---|---|
| Dev days | ~10–13 | ~18–25 | ~19–27 | ~28–41 |
| B2B pricing UX | 🔴 Spinner (lazy-load) | 🔴 Spinner (lazy-load) | ✅ Instant (token-native) | ✅ Instant (token-native) |
| UI flexibility | 🟡 Module templates | ✅ Unlimited | ✅ Unlimited | ✅ Unlimited |
| Module upgrade risk | 🟡 Theme overrides at risk | ✅ None (indexing only) | 🟡 Turbo module (low cadence) | 🟡 Turbo module (low cadence) |
| PHP compatibility | ✅ Up to PHP 8.4 | ✅ Up to PHP 8.4 | ⚠️ Turbo module PHP 8.1 only | ⚠️ Turbo module PHP 8.1 only |
| 2.4.6 compat | ⚠️ Not guaranteed since v3.16 (module) | ✅ Not applicable (headless) | ✅ Not module-dependent | ✅ Not module-dependent |
| 116-store-view handling | ✅ Auto per index | ✅ Auto per index | 🟡 Per source (manual config) | 🟡 Per source (manual config) |
| AI agent | ❌ None | ❌ None | ❌ None | ❌ None |
| Implementation support | Onboarding workshops | Onboarding workshops | ✅ Delivery Assurance (10 workshops) | ✅ Delivery Assurance |
| Existing Ayko relationship | ✅ Referral basis confirmed | ✅ Referral basis confirmed | ❌ New vendor | ❌ New vendor |
Key insight: The question is not just cost — it's what you get for the money:
| Dev cost | B2B pricing UX | UI flexibility | PHP support | Maintenance | |
|---|---|---|---|---|---|
| Algolia Basic | ~10–13 days | 🔴 Spinner (lazy-load) | 🟡 Module templates | ✅ PHP 8.4 | 🟡 Theme override risk |
| Algolia High | ~18–25 days | 🔴 Spinner (lazy-load) | ✅ Unlimited | ✅ PHP 8.4 | 🟢 Low (indexing only) |
| Coveo Tier 1 | ~19–27 days | ✅ Instant (token-native) | ✅ Unlimited | ⚠️ PHP 8.1 (Turbo module) | 🟢 Low |
| Coveo Tier 2 | ~28–41 days | ✅ Instant (token-native) | ✅ Unlimited | ⚠️ PHP 8.1 (Turbo module) | 🟢 Low |
| Coveo Tier 3 | ~44–67 days | ✅ Instant (token-native) | ✅ Unlimited | ⚠️ PHP 8.1 (Turbo module) | 🟢 Low |
Algolia High and Coveo Tier 1 are now closely comparable in both dev cost and UI capability. The residual difference is B2B pricing UX (spinner vs instant) and PHP support (Algolia ahead). Coveo's advantage is the native dictionaryFieldContext pricing and Delivery Assurance programme. Algolia's advantage is PHP 8.4 support and a more mature module ecosystem.
The only tier where Algolia's cost advantage is clear is Tier 1. If PE's ambition ends at Tier 1 — like-for-like replacement, minimal customisation, no development roadmap — Algolia is the rational choice. If PE have any ambition beyond that, Coveo is the better investment.
This section states clearly what each choice means for Penn-Elcom's business — commercially and practically. Neither option is being recommended above the other. The right answer depends on what you are trying to achieve.
| Algolia | Coveo | |
|---|---|---|
| 3-year subscription | £80,958 | £118,893 |
| Onboarding (one-time) | £4,698 | ✅ Included |
| 3-year committed total | £85,656 | £118,893 |
| Subscription delta | — | +£33,237 |
| Year 1 build (Tier 1) | ~£8–10k | ~£14–20k |
| B2B pricing workaround | +£3,800 mandatory | ✅ None |
| Est. ongoing maintenance/year | ~£2–4k | ~£0.5–1k |
| 3-year TCO estimate (Tier 1) | ~£102–108k | ~£138–146k |
| TCO delta | — | +£30–38k |
| B2B price display (66 groups) | 🔴 Deferred load / spinner | ✅ Instant, native |
| B2B price maintenance | 🔴 Ayko-owned endpoint | ✅ Self-maintaining |
| Record cap | ⚠️ 240k (language indexes may breach) | ✅ No limit |
| Thailand & China expansion | ⚠️ Requires re-quote, possible overage | ✅ No extra cost in 3yr term |
| Template / UI ownership | 🟡 Basic: module. High: Ayko owns all | ✅ Ayko owns all components |
| Bespoke feature integration | 🟡 Basic: retrofitted. High: first-class | ✅ First-class, built in |
| Module upgrade regression risk | 🟡 Basic: theme overrides at risk. High: none | 🟡 Turbo module (low cadence, PHP 8.1) |
| PHP compatibility | ✅ PHP 8.4 | ⚠️ Turbo module PHP 8.1 only |
| PE team self-service | 🔴 Dev required for most changes | ✅ Admin-driven |
| Catalogue toggle (NonTransactional) | 🔴 Hybrid server/client rewrite | ✅ Clean Headless StaticFilter |
| Recommendations | ✅ Included (1.4M units/year) | ✅ Included |
| Personalisation | 🟡 Per-user (separate Recommend API) | ✅ Integrated into search ranking |
| AI / GenAI capability | 🟡 Scripted intent only | ✅ True LLM (Tier 3) |
| Implementation support | Ticket-based | ✅ Delivery Assurance (24/7, named) |
| API stability / deprecation | Standard semver | Enterprise contract notice period |
| Algolia module upgrade risk | 🔴 Custom hooks broken historically | ✅ N/A |
Algolia costs less. The 3-year TCO advantage is approximately £30–38k — real money.
What that buys is a Tier 1 like-for-like replacement that works well for a standard ecommerce use case. Penn-Elcom is not a standard ecommerce use case. It has 66 customer groups, 116 store views, bespoke transactional logic, international expansion planned, and a search UI that has been substantially customised over years.
Every point at which PE's requirements exceed Algolia's standard assumptions — B2B pricing, language scaling, custom UI elements, module upgrade cycles — generates additional cost that does not appear in the initial estimate. Those costs are real, they are recurring, and they compound. The risk is not that Algolia fails on day one. The risk is that PE regret the decision 12–18 months in, when the module has been upgraded twice, the catalogue toggle has been rewritten, Thailand is waiting on a re-quote, and the initial cost saving has been spent on maintenance.
Coveo costs more upfront. What PE are paying for is a platform that is architected for their actual complexity — not a module that was designed for a simpler problem.
The decision comes down to one question: Is PE's ambition for search limited to what can be delivered at Tier 1, or do they want a search platform that grows with their business?
Before looking at what you might gain from a new platform, it is worth being clear about what you have right now and what each choice means for those capabilities.
Note on pricing row: ElasticSuite indexes customer-group prices server-side, meaning prices currently load with the page. This should be verified against PE's live site before using it as a decision factor — if there is already any deferred price loading in the current implementation, the Algolia comparison on this row changes.
| What PE has today | With Algolia | With Coveo |
|---|---|---|
| B2B pricing per customer group on search results | 🔴 Structural change. Prices cannot be indexed per-customer-group in Algolia's model. They must load after the page renders via a custom Magento API endpoint (PESLA-1599 — confirmed 30h 45m of bespoke work). The endpoint is permanently Ayko-owned and maintained. | ✅ Native. All 66 customer groups served via token model — no bespoke endpoint, no loading state, scales automatically to new groups. |
| Full Catalogue / Buy Online toolbar toggle | 🔴 Requires rewrite. Current implementation ties into ElasticSuite's FilterInterface and Magento's FPC cache variation — both ES-specific. For Algolia the toggle must be rebuilt as a hybrid server/client mechanism. The Algolia module was not designed for this pattern. | ✅ Clean migration. Maps to a Coveo Headless StaticFilter Alpine.js component — a purpose-built pattern for exactly this use case. More robust than the current implementation. |
| Enquiry-only product CTAs in search results | 🟡 Basic: retrofitted into module template. High: first-class Alpine component, same as Coveo. | ✅ First-class. Built into the Coveo Alpine product card component from day one. No override, no regression risk. |
| 116 store view search configuration | 🟡 Preserved, operationally heavier. Algolia creates one index per store view. Synonyms, rules, and relevance must be managed per index. No bulk tooling confirmed. | 🟡 Preserved. Option B (6 per-website sources) reduces admin overhead vs 116 sources. Coveo pipeline rules are shared across sources — changes apply broadly. New store views map to existing source configuration. |
| Multi-language search quality (9 active language store views) | 🟡 Preserved but requires separate indexes. Language-specific indexes are not confirmed within the 240k record quote — may push PE toward or over the cap. Configuration per language index needed. | 🟡 Preserved. Each language configured at source level. No record cap. But Coveo source configuration for 9+ languages still requires initial setup time. |
| Product badge rendering on search results | 🟡 Preserved but dev-dependent. New badge types require a developer to modify the Algolia module template. Each module update is a regression risk. | ✅ Preserved and becomes self-service. Field-conditional badge logic managed in Coveo admin after initial build. |
| Thailand and China stores (Year 2) | 🔴 Requires re-quote. Thai and Chinese language indexes need dedicated indexes, not in scope of current 240k record quote. PE would return to Algolia for an amended contract. | ✅ Within existing contract. Fits in 3-year term at no extra subscription cost. Source configuration only. |
| Extending search with new features over time | 🟡 Basic: constrained by module. High: open — Ayko owns all components, same as Coveo. | ✅ Open. Coveo Headless + Alpine — Ayko owns all components. New features are additive. |
Algolia asks: - Accept deferred B2B pricing (structural — not a configuration choice) - Permanently maintain a custom Ayko pricing endpoint - Accept that your bespoke UI features (toggle, enquiry CTAs, badges) require dev work to maintain around the module's template ownership - Budget for a record count re-quote when Thailand and China go live - Accept higher ongoing dev cost as customisation depth increases
Coveo asks: - Pay £33,237 more over 3 years (£220/month) - Accept a higher Year 1 build cost (£6–10k more at Tier 1) - Accept that the Coveo Turbo M2 module is newer and less battle-tested than Algolia's (though Ayko has reviewed and patched it) - Accept that Coveo's renewal price is list price at the time — not a fixed escalator. It could go up or down. - Accept a more complex initial implementation that requires more Ayko input to set up correctly
Neither list is fabricated. Both platforms have real costs and real trade-offs for PE's specific situation.
Algolia is cheaper in year 1 and over the subscription term. For a business whose search ambitions are genuinely Tier 1 — better relevance, standard facets, no major customisation roadmap — that is a completely rational choice and they would be overpaying for Coveo.
The question is whether PE's actual profile fits that description. With 66 customer groups, 116 store views, bespoke transactional logic, planned international expansion, and a history of investing in custom search features, the evidence suggests it does not. The Algolia cost savings are real — but so are the additional costs that follow from PE's specific complexity.
PE should make this decision with both lists in front of them.
| # | Question | Answer |
|---|---|---|
| 1 | Store view count | 121 rows in DB (116 active store views, 6 websites) — confirmed by DB scan |
| 2 | Customer group count | 66 groups in DB (Will cited 69 — ~3 likely inactive) |
| 3 | Catalog rule prices | No active catalog rules — confirmed by PE. CatalogRuleOptimisation is dead code. Cart price rules at checkout unaffected. |
| 4 | Coveo contract status | Not signed — introductory pitch stage. Delivery Assurance included in contract. |
| 5 | Frontend framework | Alpine.js — confirmed. Coveo PS also recommended Headless SDK over Atomic for this use case. |
| 6 | ES removal post-migration | Must be retained as fallback — not removed, kept as graceful degradation target |
| 7 | AI agent priority | PE to confirm — general cost/scalability/data complexity are current priorities |
| 8 | Designs before dev | Yes — required for Tier 2+ |
| 9 | B2B price field strategy | Dictionary fields confirmed — dictionaryFieldContext in search token. Ashley demoed group→value price array. Single index, no duplication. |
| 10 | Source structure | Three options confirmed by Coveo written Q&A — (A) 116 per-store-view sources, (B) 6 per-website sources via Tracking ID + Storefront Association (both work today, no connector changes), (C) multi-market single source (PS commitment, not yet built). Option B likely the pragmatic starting point. |
| 11 | Translation quality | PESLA-572 — substantial translation project completed for de, fr, es, pt, pl, nl store views. URL structure migrated. hreflang implemented. Translations appear complete for 6 language views. |
| 12 | ElasticSuite license | Open-source (community) edition — no enterprise license cost. Confirmed by composer deps. |
| 13 | Coveo tier + QPM | Enterprise “Personalisation as you go” at 100,000 QPM — confirmed by Robert from the Coveo quote email. |
| 14 | Provider questions submitted | Both Coveo and Algolia contacted 2026-07-08 — responses received 2026-07-10. See C1–C12 and A1–A14 below. |
| C1 | Coveo: what counts as a query at 100k QPM? | PLP page load = 1 query. Each facet selection, pagination, sort = additional query. |
| C2 | Coveo: QPM cap — hard throttle or overage? | Not a hard monthly cap. Evaluated across subscription term. No auto-restriction — commercial review if exceeded. |
| C3 | Coveo: Is Generative Answering (RGA) included? | Separate. Measured in GQPM — not standard QPM. |
| C4 | Coveo: Source architecture options? | Three options confirmed: (A) 116 per-store-view sources, (B) 6 per-website sources via Tracking ID + Storefront Association — both work today, no connector changes. (C) multi-market single source — PS commits to connector enhancements if chosen, not yet built. Source count does not affect subscription cost. |
| C5 | Coveo: Partial price update or full re-push? | Partial updates supported. Individual dictionary values updated without re-indexing full record. Turbo connector supports this. |
| C6 | Coveo: Dictionary field key limits at 66 groups? | 66 is well within limits. Reference customer has 10,000 keys per dictionary (numeric values). |
| C7 | Coveo: Batching/chunking for 7,800 × 116 store views? | Batch by payload size, not product count. |
| C8 | Coveo: B2B connector auto-populate dictionary field? | Not out of the box. Store-scoped pricing: yes. Customer-group pricing: requires small connector enhancement — Coveo says "relatively minor." |
| C9 | Coveo: Delivery Assurance workshops — flexible? | Yes. Can dedicate sessions to Push API schema, 66 price groups, SKU tokenisation before any code written. |
| C10 | Coveo: Implementation review scope? | End-to-end — frontend search, analytics, query pipeline config, and go-live readiness. |
| C11 | Coveo: Search API SLA? | Search API: 99.99% (5 nines in NA). Push API: no separate SLA stated. |
| C12 | Coveo: Multi-language tokenisation config? | Per-document "language" field. Current connector separates by locale/store view. Multi-market approach removes this constraint but connector not yet built. |
| A1 | Algolia: Premium tier minimum commitment? | 12-month minimum. Pricing scoped per project. |
| A2 | Algolia: Record count at PE's scale? | Algolia scopes PE at 2.7M records (store views + sort replicas). 240k quote cap is significantly underscoped. |
| A3 | Algolia: Delivery Assurance equivalent? | Onboarding service with PS workshops. Less structured than Coveo's 10-workshop DA. |
| A4 | Algolia: 20-price limit — hard or soft? | Recommended ceiling, not a hard limit. Practical max: 100 price lists per product. |
| A5 | Algolia: Lazy-load pricing — officially supported? | Documented, well-established approach. Implementation is bespoke dev work owned by Ayko. |
| A6 | Algolia: Lazy-load latency / caching? | Entirely depends on Magento pricing API — outside Algolia's scope. |
| A7 | Algolia: Secured API Keys — OOTB in M2 module? | Keys are virtual, no rate limit. Not supported OOTB in M2 module. Use unretrievableAttributes for field visibility. |
| A8 | Algolia: Compatible with Magento 2.4.6-p15 + B2B? | 2.4.6 not guaranteed since v3.16. No known Shared Catalog issues. |
| A9 | Algolia: Breaking changes for bespoke themes? | Cannot officially support customised solutions. Every release documents breaking changes. |
| A10 | Algolia: Frontend override depth — theme vs fork? | Three valid paths: (1) indexing only + custom FE, (2) InstantSearch + theme override, (3) v3.18+ Adapter module (SSR). |
| A11 | Algolia: ElasticSuite migration path? | No specific guide. Indexing/frontend/faceting migrate cleanly; low-level analyzer tuning does not. |
| A12 | Algolia: Merchandising rules across 116 indexes — shareable? | Propagatable via direct targeting or wildcard. |
| A13 | Algolia: Infix SKU matching configurable? | Achievable via API-level config. Not in M2 module UI. |
| A14 | Algolia: Built-in fallback to native Magento search? | No built-in fallback. Requires custom implementation. |
Provider Q&A responses received 2026-07-10. Qs C1–C12 and A1–A14 now resolved in §10. Below: what is still outstanding.
The operationally critical question that architecture analysis alone can't answer is support — if there's a bug caused by a specific bit of data that takes search offline, how soon would they fix it?
| Failure scenario | Algolia ownership | Coveo ownership |
|---|---|---|
| Platform API outage | ✅ Algolia — covered by SLA | ✅ Coveo — covered by enterprise SLA |
| Module/SDK bug | ✅ Algolia (module is theirs) | ✅ Coveo (SDK is theirs) |
| Magento data edge case corrupts index sync | 🟡 Grey zone — Algolia may defer to Ayko | 🟡 Grey zone — Coveo PS familiarity helps |
| PESLA-1599 endpoint slow/erroring (prices offline) | ❌ Ayko's responsibility — Algolia cannot help | ❌ N/A — doesn't exist in Coveo architecture |
| Custom template/hook causing bad results | ❌ Ayko's responsibility | ❌ Ayko's responsibility |
| Token endpoint failure (Coveo only) | N/A | ❌ Ayko's responsibility (simple, single point) |
The PESLA-1599 gap is the material difference. If prices stop rendering — which is a realistic failure mode for the lazy-load endpoint — that is 100% Ayko's problem to diagnose and fix. Algolia will not engage. Coveo doesn't have this failure mode because pricing is handled in the token, not in a bespoke endpoint.
Coveo Enterprise includes 24/7 support with named contacts and a Delivery Assurance team familiar with the implementation. Because Coveo PS reviewed the architecture during workshops, they understand the codebase when something goes wrong — faster triage, less finger-pointing.
Ongoing maintenance cost is not reflected in the tier estimates and must be considered separately.
| Maintenance item | Frequency | Notes |
|---|---|---|
| Module version upgrades | Per Algolia release cycle | Each upgrade risks breaking bespoke hooks (PESLA-1599 pricing, custom product card, non-transactional CTA). Requires regression test across key store views. |
| PESLA-1599 endpoint maintenance | As Magento pricing logic changes | If PE add customer groups, change tier pricing structure, or modify shared catalog rules, the custom pricing endpoint may need updating. |
| Index configuration (116 stores) | Ongoing | New attributes, new facets, merchandising rules must be configured per-index in Algolia dashboard. No bulk tooling confirmed. |
| Synonym / relevance management | Ongoing | Per-index — changes across all 116 store views require either manual repetition or API scripting. |
| Badge management | Per new badge type | New condition-based badge requires dev involvement to add template logic. |
| Maintenance item | Frequency | Notes |
|---|---|---|
| Coveo Turbo module upgrades | Low cadence (2 commits currently) | Unknown upgrade risk — module is immature. Fewer upgrades expected but less battle-tested. Parity question sent to Coveo PS. |
| Headless SDK / Search API deprecation | Per Coveo release cycle | Headless SDK is npm/semver — pinned version stays stable until you choose to upgrade. REST API (/rest/search/v2) has been stable for years. Enterprise contracts include formal deprecation notice periods. Not a quarterly forced cycle like Shopify. Major SDK version bumps (v1→v2→v3) may require frontend updates but are infrequent. Deprecation policy question sent to Coveo. |
| Push API schema changes | Only if PE's product data model changes | Adding a new price group = add a dictionary field key. No re-architecture required. |
| Source configuration | Only if new websites/store views added | New store view = new source config. More manual than Algolia's auto-creation. |
| Merchandising / relevance tuning | Ongoing | Shared pipeline rules — changes apply across all sources. PE team can manage some of this via Coveo admin without dev. |
| Badge management | PE self-serve | Field-conditional rendering — PE team can add/modify badge conditions in Coveo admin without dev involvement. |
| Subscription review | Annual | QPM tier vs actual usage — ensure PE aren't overprovisioned or hitting cap. |
| Algolia | Coveo | |
|---|---|---|
| Module upgrade risk | Higher (frequent releases, custom hooks at risk) | Lower but unknown (immature module). SDK pinned — stable until deliberately upgraded. |
| API deprecation risk | Standard semver (same model as Coveo) | Enterprise notice period in contract. Not Shopify-style quarterly forced cycle. |
| B2B pricing maintenance | Bespoke endpoint (Ayko dependency) | Token context (self-maintaining) |
| Index/source management | Per-index, 116 stores, no bulk tool confirmed | Shared pipeline, lower overhead |
| Badge/merchandising self-service | ❌ Dev required per change | ✅ PE self-serve |
| PE team autonomy | Low | Higher |
Over a 3-year contract, Coveo's lower ongoing maintenance overhead is a meaningful TCO advantage that does not appear in the Tier implementation estimates.
The quoted plan (Coveo for Commerce) bundles three things:
| Recommendation type | Coveo | Algolia (Recommend — included in Q-55286) |
|---|---|---|
| Frequently Bought Together | ✅ ML-based | ✅ ML-based |
| Viewed Also Viewed | ✅ ML-based | ✅ ML-based |
| Trending / Popular | ✅ | ✅ |
| Personalised (per user) | ✅ Integrated into search ranking itself | ✅ Separate Recommend API call |
| Visual similarity | ❌ | ✅ (requires image data) |
| Query-based | ✅ | ✅ |
| Rules-based override | ✅ Business-Aware Ranking in admin | ✅ Merchandising rules per index |
Both are ML-based, not purely rule-driven. Neither replaces Magento's native Product Recommendations (Adobe Sensei) — that's a separate module.
Both platforms use the same model: instrument the frontend to fire events that train the ML. Quality of recommendations = quality + volume of event data.
| Event | When it fires | Required for | PE note |
|---|---|---|---|
| Search click | User clicks a product from search results | All recommendation types, relevance | Largely automatic via both platforms' modules/SDK |
| PDP view | Any product page load | Viewed Also Viewed, Related Products | Needs wiring on every PDP load |
| Add to cart | Product added to cart (ideally with query ID) | Frequently Bought Together | Magento observer or GTM |
| Purchase / order complete | Order confirmed, all items + values | Frequently Bought Together, Trending, Personalisation | Magento observer on order success |
| Enquiry submission | Enquiry form completed | Treated as conversion | PE-specific — custom event mapping required. Neither platform has a native enquiry type. |
| Recommendation click | User clicks a recommended item | Training the recommendation model | Automatic once recommendation widgets are built |
| Facet / filter use | Filter applied | Relevance tuning | Largely automatic |
The M2 module ships with Insights API integration. Search result click tracking is largely automatic once enabled in module config. PDP view, cart, and purchase events need Magento observer wiring — hooks exist in the module but need configuring. User token = Magento customer ID for logged-in users, cookie for guests. Important caveat at Tier 2/3: as module templates are increasingly overridden, the module's automatic Insights event chain can break silently. Heavily customised implementations may need manual event rewiring — putting them in the same position as a bespoke build anyway, but with less control.
The SDK controllers (ResultList, SearchBox, FacetList) fire search and click analytics automatically when properly configured. PDP views, cart, and purchase events need wiring via Coveo's analytics actions (logProductClick, logCartAction, logPurchase). In practice, not an issue: since all Coveo components are built as bespoke Alpine.js components from scratch, a single reusable tracking abstraction (e.g. a useTracking() helper) can be baked into the component templating layer and imported across every search, PLP, and recommendation component. Event dispatch is consistent, centralised, and doesn't depend on module hooks. This is a meaningful implementation advantage over Algolia at Tier 2+.
Neither platform can produce meaningful recommendations on day one.
PE have 116 store views across the EU. For anonymous users, cookie-based behaviour tokens require consent under GDPR before any tracking fires. Logged-in B2B users are likely covered by existing platform terms, but anonymous tracking needs checking against PE's cookie policy before instrumentation goes live.