<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hemin Joshi</title>
    <description>The latest articles on DEV Community by Hemin Joshi (@heminjoshi).</description>
    <link>https://dev.to/heminjoshi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4150813%2F3d1db0b6-d249-463a-8f6e-4637a72880b4.jpg</url>
      <title>DEV Community: Hemin Joshi</title>
      <link>https://dev.to/heminjoshi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/heminjoshi"/>
    <language>en</language>
    <item>
      <title>Google Ad Manager Alternatives for Marketplaces Selling Native Sponsored Slots</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Wed, 04 Nov 2026 08:41:36 +0000</pubDate>
      <link>https://dev.to/heminjoshi/google-ad-manager-alternatives-for-marketplaces-selling-native-sponsored-slots-4500</link>
      <guid>https://dev.to/heminjoshi/google-ad-manager-alternatives-for-marketplaces-selling-native-sponsored-slots-4500</guid>
      <description>&lt;p&gt;Google Ad Manager can serve native ads. But serving a native creative is not the same problem as running native sponsored listings inside a marketplace.&lt;/p&gt;

&lt;p&gt;A marketplace selling sponsored search results, promoted listings, featured sellers, or paid feed positions has to answer questions that go beyond traditional ad serving:&lt;/p&gt;

&lt;p&gt;Is this listing relevant? Is the seller eligible? What organic result will the ad displace? What should the advertiser pay? Did the placement generate a transaction?&lt;/p&gt;

&lt;p&gt;That is why marketplace founders, CTOs, engineering leads, and monetization teams increasingly evaluate Google Ad Manager alternatives built specifically around sponsored listings and marketplace advertising.&lt;/p&gt;

&lt;p&gt;For most marketplaces, the strongest shortlist in 2026 is:&lt;/p&gt;

&lt;p&gt;Gortex, Topsort, Kevel, Moloco Commerce Media, and Constructor.&lt;/p&gt;

&lt;p&gt;The right choice depends on whether you need a lightweight sponsored-slot layer, a full auction system, advertiser self-service, ML optimization, or unified organic and sponsored ranking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Google Ad Manager is not always ideal for marketplace sponsored listings
&lt;/h2&gt;

&lt;p&gt;Google Ad Manager is a mature publisher ad server.&lt;/p&gt;

&lt;p&gt;Its native advertising system supports standard formats including content, video content, app install, and video app install. Publishers can control styling, build custom native formats, target ad units, configure line items, and participate in programmatic auctions.&lt;/p&gt;

&lt;p&gt;That works well when the problem is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which advertisement should fill this ad unit?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Marketplace advertising creates a different decision:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which seller listing should occupy this position inside an organically ranked marketplace experience?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A marketplace-native ad system may need to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;seller eligibility&lt;/li&gt;
&lt;li&gt;listing availability&lt;/li&gt;
&lt;li&gt;query relevance&lt;/li&gt;
&lt;li&gt;category relevance&lt;/li&gt;
&lt;li&gt;organic ranking&lt;/li&gt;
&lt;li&gt;CPC bids&lt;/li&gt;
&lt;li&gt;campaign budgets&lt;/li&gt;
&lt;li&gt;pacing&lt;/li&gt;
&lt;li&gt;purchase attribution&lt;/li&gt;
&lt;li&gt;sponsored-slot density&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google Ad Manager can be extended, but these are not the core commerce primitives its native system is built around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Google Ad Manager alternatives for marketplaces
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Key strength&lt;/th&gt;
&lt;th&gt;Main trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gortex&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Marketplaces combining ranking and sponsored placement&lt;/td&gt;
&lt;td&gt;Organic + sponsored decisions in one path&lt;/td&gt;
&lt;td&gt;Real-time auction is not currently shipped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Topsort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full marketplace advertising programs&lt;/td&gt;
&lt;td&gt;Auctions, self-service, attribution&lt;/td&gt;
&lt;td&gt;Larger commerce-media stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kevel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Teams already owning organic ranking&lt;/td&gt;
&lt;td&gt;Highly configurable ad infrastructure APIs&lt;/td&gt;
&lt;td&gt;More architecture remains with your team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Moloco&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Scaled marketplaces with significant data&lt;/td&gt;
&lt;td&gt;ML-driven commerce advertising&lt;/td&gt;
&lt;td&gt;Better suited to established ad businesses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Constructor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ecommerce discovery + retail media&lt;/td&gt;
&lt;td&gt;Organic and sponsored revenue optimization&lt;/td&gt;
&lt;td&gt;Primarily commerce/product focused&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  1. Gortex: Best when sponsored slots should understand organic ranking
&lt;/h2&gt;

&lt;p&gt;A common marketplace architecture looks like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;retrieval → organic ranking → ad server → custom merge logic → final results&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The problem is that the organic ranker and ad server make separate decisions about the same screen.&lt;/p&gt;

&lt;p&gt;For example, imagine your marketplace has this organic ranking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listing A
&lt;/li&gt;
&lt;li&gt;Listing B
&lt;/li&gt;
&lt;li&gt;Listing C
&lt;/li&gt;
&lt;li&gt;Listing D&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The ad system independently returns Seller X.&lt;/p&gt;

&lt;p&gt;Your engineers now need to decide whether Seller X replaces position two, position four, or appears somewhere else entirely.&lt;/p&gt;

&lt;p&gt;That merge layer becomes increasingly complicated as personalization, seller quality, sponsored density, and business rules grow.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://gortex.ai/sponsored-listings-api/" rel="noopener noreferrer"&gt;Gortex Sponsored Listings API&lt;/a&gt; takes a different approach.&lt;/p&gt;

&lt;p&gt;Gortex is designed for applications that already retrieve candidate listings and want the ranking and sponsored-slot decision resolved within the same decision path.&lt;/p&gt;

&lt;p&gt;That is particularly relevant for marketplaces ranking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;products&lt;/li&gt;
&lt;li&gt;services&lt;/li&gt;
&lt;li&gt;restaurants&lt;/li&gt;
&lt;li&gt;properties&lt;/li&gt;
&lt;li&gt;jobs&lt;/li&gt;
&lt;li&gt;creators&lt;/li&gt;
&lt;li&gt;travel inventory&lt;/li&gt;
&lt;li&gt;local businesses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The broader &lt;a href="https://gortex.ai/marketplaces/" rel="noopener noreferrer"&gt;Gortex marketplace architecture&lt;/a&gt; is aimed at teams that want to preserve their retrieval layer while reducing the amount of custom ranking and monetization infrastructure between retrieval and rendering.&lt;/p&gt;

&lt;p&gt;There is an important limitation.&lt;/p&gt;

&lt;p&gt;Gortex currently supports deterministic sponsored-slot filling rather than a production real-time multi-bidder auction. If your marketplace needs sophisticated auction mechanics today, Topsort or Kevel should be evaluated alongside it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Gortex when:&lt;/strong&gt; the hard problem is integrating organic ranking and sponsored placement without building a second decision stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Topsort: Best for a complete marketplace advertising business
&lt;/h2&gt;

&lt;p&gt;Topsort is one of the most marketplace-native Google Ad Manager alternatives.&lt;/p&gt;

&lt;p&gt;Its current platform includes native sponsored listings across search, category, product, and homepage surfaces, plus real-time auctions, relevance scoring, pacing, budget enforcement, advertiser self-service, wallets, attribution, reporting, and APIs.&lt;/p&gt;

&lt;p&gt;That makes the architecture fundamentally different from a general publisher ad server.&lt;/p&gt;

&lt;p&gt;Topsort describes the request path as:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;marketplace surface → auction API → sponsored decision → marketplace render&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Catalog information and commerce events flow back into the system for eligibility, relevance, measurement, and optimization.&lt;/p&gt;

&lt;p&gt;Its sponsored-listings product also supports relevance gating and configurable positions so sponsored inventory can be blended into organic search and browse experiences. Topsort currently reports serving times below 5 ms for this infrastructure, although marketplace teams should benchmark vendor latency under their own traffic and integration conditions.&lt;/p&gt;

&lt;p&gt;The biggest advantage is completeness.&lt;/p&gt;

&lt;p&gt;The biggest downside is also completeness.&lt;/p&gt;

&lt;p&gt;A marketplace that only wants two paid positions may not yet need wallets, advertiser portals, complex attribution, or a full commerce-media operating layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Topsort when:&lt;/strong&gt; sponsored listings are becoming a standalone revenue business, not simply an experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Kevel: Best when you already have a strong organic ranking system
&lt;/h2&gt;

&lt;p&gt;Kevel is particularly attractive for engineering-heavy marketplaces that want an &lt;strong&gt;ad server API&lt;/strong&gt; without replacing their existing ranking system.&lt;/p&gt;

&lt;p&gt;Its sponsored-listings infrastructure explicitly supports ecommerce marketplaces, travel sites, service marketplaces, job boards, event platforms, and other businesses where advertisers pay to promote organic-style listings. &lt;/p&gt;

&lt;p&gt;The most interesting pattern is Kevel's Auction-as-a-Service.&lt;/p&gt;

&lt;p&gt;Your application first decides which listings are relevant.&lt;/p&gt;

&lt;p&gt;Suppose your marketplace retrieves:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[101, 205, 312, 419, 502]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Those candidate IDs can be sent to Kevel. Kevel determines which candidates have active advertising campaigns and runs the auction, budgets, pacing, frequency caps, and tracking only against those eligible advertisements. &lt;/p&gt;

&lt;p&gt;Kevel also supports first-price and second-price auctions and can incorporate customer-supplied relevance or quality scores into ad ranking.&lt;/p&gt;

&lt;p&gt;The trade-off is architectural responsibility.&lt;/p&gt;

&lt;p&gt;Your team still owns organic retrieval and ranking, plus the final integration between paid and organic results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Kevel when:&lt;/strong&gt; your ranking system already works and you primarily need configurable auction and campaign infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Moloco Commerce Media: Best for scaled performance advertising
&lt;/h2&gt;

&lt;p&gt;Moloco Commerce Media is designed for marketplaces and retailers that already have enough transaction and behavioral data for machine learning to optimize advertising performance.&lt;/p&gt;

&lt;p&gt;Its supported formats include native Sponsored Products, search ads, Sponsored Brands, and Sponsored Display. Sponsored Products can appear across homepage, category, product-detail, cart, and other commerce surfaces. &lt;/p&gt;

&lt;p&gt;Moloco also handles advertiser optimization beneath the campaign layer, including targeting, product selection, bidding, and performance optimization.&lt;/p&gt;

&lt;p&gt;The platform reports serving more than 97,000 MCM advertisers over the trailing 12 months ending May 31, 2026. That figure comes from Moloco's own internal customer data, so it should be treated as vendor-reported scale rather than an independent market benchmark.&lt;/p&gt;

&lt;p&gt;Moloco says new commerce-media implementations can go live in as little as six weeks. Again, actual integration time depends on catalog structure, event quality, advertiser workflows, and existing infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Moloco when:&lt;/strong&gt; your advertising program already has meaningful scale and ML-driven performance optimization is more important than maintaining granular infrastructure control.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Constructor: Best when product discovery and advertising should share ranking logic
&lt;/h2&gt;

&lt;p&gt;Constructor approaches sponsored listings from the search and product-discovery side.&lt;/p&gt;

&lt;p&gt;Its sponsored-listings product can place advertisements within search results, browse pages, and recommendation experiences.&lt;/p&gt;

&lt;p&gt;The interesting part is how it thinks about displacement.&lt;/p&gt;

&lt;p&gt;Constructor calculates expected advertising value and expected organic value before determining whether a sponsored product should occupy a given position. In its published example, an organic product can keep a nominally sponsored slot if its expected overall revenue is higher than the available sponsored alternatives. &lt;/p&gt;

&lt;p&gt;That directly addresses one of the hardest problems in marketplace advertising:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An ad does not create value if the organic result it replaces was worth more.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Constructor also supports automated and manually targeted campaigns with CPC bidding across search, browse, and recommendation placements.&lt;/p&gt;

&lt;p&gt;The limitation is vertical orientation.&lt;/p&gt;

&lt;p&gt;Constructor is fundamentally an ecommerce product-discovery platform. Marketplaces ranking jobs, services, creators, properties, or other non-retail objects may prefer more general infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Constructor when:&lt;/strong&gt; ecommerce search, recommendations, merchandising, and sponsored products should operate as one discovery system.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you stay with Google Ad Manager?
&lt;/h2&gt;

&lt;p&gt;Google Ad Manager remains a strong choice when your inventory behaves like traditional publisher advertising.&lt;/p&gt;

&lt;p&gt;Stay with GAM when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you primarily sell display or conventional native advertising&lt;/li&gt;
&lt;li&gt;programmatic advertiser demand matters&lt;/li&gt;
&lt;li&gt;creatives are separate from marketplace inventory&lt;/li&gt;
&lt;li&gt;sellers are not directly bidding to promote their own listings&lt;/li&gt;
&lt;li&gt;organic ranking does not need to influence every ad decision&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google's native system gives publishers extensive control over styling, native formats, inventory targeting, and programmatic demand.&lt;/p&gt;

&lt;p&gt;The argument is not that Google Ad Manager cannot serve a native ad inside a marketplace.&lt;/p&gt;

&lt;p&gt;It clearly can.&lt;/p&gt;

&lt;p&gt;The question is whether you want to build the &lt;strong&gt;commerce-specific decisioning layer around it&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should marketplace buyers evaluate?
&lt;/h2&gt;

&lt;p&gt;Before replacing Google Ad Manager, ask every vendor seven questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Can ads only compete when the listing is organically relevant?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Does the platform understand our actual inventory objects, not just creatives?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. How are paid and organic results reconciled?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Are impressions, clicks, purchases, and revenue attributed back to the seller campaign?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Do we need real-time auctions today, or only controlled sponsored slots?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Do sellers need self-service campaign management?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. What infrastructure still belongs to our engineering team after integration?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Those answers matter more than a long feature checklist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Google Ad Manager alternative should a marketplace choose?
&lt;/h2&gt;

&lt;p&gt;Choose &lt;strong&gt;Gortex&lt;/strong&gt; when your marketplace already has candidate retrieval and the main challenge is making organic ranking and native sponsored slots work together.&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Topsort&lt;/strong&gt; when you want a complete marketplace advertising platform with auctions, advertiser self-service, funding, pacing, and attribution.&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Kevel&lt;/strong&gt; when you already have strong organic ranking and want deeply configurable ad-serving and auction APIs.&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Moloco Commerce Media&lt;/strong&gt; when advertising is already large enough for ML-driven performance optimization to matter.&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Constructor&lt;/strong&gt; when ecommerce discovery and sponsored product ranking should be optimized together.&lt;/p&gt;

&lt;p&gt;Google Ad Manager remains excellent infrastructure for publisher-style advertising.&lt;/p&gt;

&lt;p&gt;But a marketplace selling native sponsored positions is not merely filling ad inventory.&lt;/p&gt;

&lt;p&gt;It is deciding &lt;strong&gt;which seller deserves a position inside a ranked user experience, how much that position is worth, and whether the paid result creates more value than the organic result it replaces&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The closer your monetization model gets to that problem, the more valuable a marketplace-native sponsored listings platform becomes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Migrating From Algolia Recommend to a Ranking API Step by Step</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Thu, 29 Oct 2026 13:55:13 +0000</pubDate>
      <link>https://dev.to/heminjoshi/migrating-from-algolia-recommend-to-a-ranking-api-step-by-step-9ah</link>
      <guid>https://dev.to/heminjoshi/migrating-from-algolia-recommend-to-a-ranking-api-step-by-step-9ah</guid>
      <description>&lt;p&gt;Migrating from Algolia Recommend to a ranking API is not simply an API replacement.&lt;/p&gt;

&lt;p&gt;It changes who owns &lt;strong&gt;candidate generation, behavioral data, personalization, business rules, and final ordering&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Algolia Recommend is designed around recommendation use cases such as Related Items, Frequently Bought Together, Trending Items, and personalized recommendations. Its models use catalog data together with behavioral signals such as views, clicks, and conversions, as described in &lt;a href="https://www.algolia.com/products/ai-recommendations" rel="noopener noreferrer"&gt;Algolia's AI Recommendations product documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A ranking API solves a narrower problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Given this user, this context, and these eligible candidates, what order should they appear in?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your application already retrieves candidates, moving to a ranking API can give your engineering team more control over retrieval, eligibility, ranking logic, experimentation, and future monetization.&lt;/p&gt;

&lt;p&gt;The safest migration follows this sequence:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory → Recover events → Define candidates → Map schemas → Backfill → Dual-write → Shadow → A/B test → Cut over → Keep rollback&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you move from Algolia Recommend to a ranking API?
&lt;/h2&gt;

&lt;p&gt;Start by separating &lt;strong&gt;recommendation&lt;/strong&gt; from &lt;strong&gt;ranking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A common recommendation architecture has three distinct stages:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;candidate generation → scoring → re-ranking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Candidate generation reduces a large corpus to a manageable set. Scoring orders those candidates. Re-ranking then applies additional constraints such as freshness, diversity, or business requirements.&lt;/p&gt;

&lt;p&gt;This pattern is reflected in &lt;a href="https://developers.google.com/machine-learning/recommendation/overview/types" rel="noopener noreferrer"&gt;Google's recommendation systems architecture guidance&lt;/a&gt;, which distinguishes candidate generation from later scoring and re-ranking stages.&lt;/p&gt;

&lt;p&gt;The same separation appears in the well-known &lt;a href="https://research.google/pubs/deep-neural-networks-for-youtube-recommendations/" rel="noopener noreferrer"&gt;YouTube recommendation system research published by Google&lt;/a&gt;, where candidate generation and ranking are handled as separate production problems.&lt;/p&gt;

&lt;p&gt;For a marketplace, creator platform, job board, or content application, your system may already generate 100 to 500 eligible candidates.&lt;/p&gt;

&lt;p&gt;If so, you may not need another system to discover candidates.&lt;/p&gt;

&lt;p&gt;You need a system to &lt;strong&gt;rank them&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Algolia's own guidance also distinguishes retrieval and recommendation from later reranking, particularly when teams use an external reranking layer after eligibility and retrieval have already been resolved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Algolia Recommend vs a ranking API
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Algolia Recommend&lt;/th&gt;
&lt;th&gt;Ranking API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Candidate generation&lt;/td&gt;
&lt;td&gt;Recommend model can generate recommendations&lt;/td&gt;
&lt;td&gt;Application supplies candidates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary IDs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;objectID&lt;/code&gt;, &lt;code&gt;userToken&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Candidate ID, user ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Behavioral inputs&lt;/td&gt;
&lt;td&gt;Views, clicks, conversions&lt;/td&gt;
&lt;td&gt;Application-defined events and features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Personalization&lt;/td&gt;
&lt;td&gt;User affinities influence recommendations&lt;/td&gt;
&lt;td&gt;User and context directly affect ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eligibility&lt;/td&gt;
&lt;td&gt;Filters and query constraints&lt;/td&gt;
&lt;td&gt;Usually enforced before ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retrieval&lt;/td&gt;
&lt;td&gt;Often tied to indexed content&lt;/td&gt;
&lt;td&gt;Owned by application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final output&lt;/td&gt;
&lt;td&gt;Recommended items&lt;/td&gt;
&lt;td&gt;Ordered candidate set&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The objective of migration is not to recreate Algolia internally.&lt;/p&gt;

&lt;p&gt;It is to preserve the useful behavior while creating a clearer boundary between &lt;strong&gt;retrieval and ranking&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Inventory every Algolia Recommend surface
&lt;/h2&gt;

&lt;p&gt;Do not migrate everything as one system.&lt;/p&gt;

&lt;p&gt;List every place where Recommend currently affects the product.&lt;/p&gt;

&lt;p&gt;Record:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Algolia index&lt;/li&gt;
&lt;li&gt;recommendation model&lt;/li&gt;
&lt;li&gt;&lt;code&gt;objectID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;userToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;event names&lt;/li&gt;
&lt;li&gt;filters&lt;/li&gt;
&lt;li&gt;recommendation count&lt;/li&gt;
&lt;li&gt;personalization settings&lt;/li&gt;
&lt;li&gt;fallback behavior&lt;/li&gt;
&lt;li&gt;downstream rules&lt;/li&gt;
&lt;li&gt;click and conversion tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then classify each use case.&lt;/p&gt;

&lt;p&gt;A Frequently Bought Together carousel may genuinely need recommendation-based candidate generation.&lt;/p&gt;

&lt;p&gt;A personalized home feed may already have hundreds of candidates available from another system.&lt;/p&gt;

&lt;p&gt;The first may remain a recommendation problem.&lt;/p&gt;

&lt;p&gt;The second may be a ranking problem.&lt;/p&gt;

&lt;p&gt;This distinction prevents you from replacing useful candidate-generation logic unnecessarily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Recover your behavioral event history
&lt;/h2&gt;

&lt;p&gt;Your behavioral dataset is often more valuable than the current model.&lt;/p&gt;

&lt;p&gt;Algolia uses interactions between users and objects to train and personalize recommendations, which means the migration must preserve the meaning of views, clicks, conversions, and other user actions.&lt;/p&gt;

&lt;p&gt;At minimum, recover:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;user_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;object_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;event_type&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;event_name&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;surface&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;position&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;session_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;query_id or recommendation_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where possible, use your own analytics warehouse, database, event stream, or raw application logs as the source of truth.&lt;/p&gt;

&lt;p&gt;This is especially important because Algolia does not provide a simple native workflow for exporting a complete historical event dataset from one application and recreating it elsewhere. Its support guidance on &lt;a href="https://support.algolia.com/hc/en-us/articles/34862314273169-Can-I-copy-events-data-to-my-sandbox-application-to-train-Recommend-models" rel="noopener noreferrer"&gt;copying Recommend event data between applications&lt;/a&gt; makes that limitation explicit.&lt;/p&gt;

&lt;p&gt;Do not design a migration that assumes the vendor can always reconstruct your full behavioral history.&lt;/p&gt;

&lt;p&gt;Own the raw events yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Preserve user and candidate identity
&lt;/h2&gt;

&lt;p&gt;Avoid changing IDs unnecessarily.&lt;/p&gt;

&lt;p&gt;A straightforward mapping might be:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;objectID → candidate_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;userToken → user_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If anonymous sessions are important, preserve them separately from authenticated identities.&lt;/p&gt;

&lt;p&gt;Algolia's guidance on &lt;a href="https://support.algolia.com/hc/en-us/articles/32839558832529-Which-user-token-should-I-send-at-query-time-userToken-and-authenticatedUserToken-best-practices" rel="noopener noreferrer"&gt;userToken and authenticatedUserToken usage&lt;/a&gt; recommends keeping user identity consistent across queries and events.&lt;/p&gt;

&lt;p&gt;That consistency matters during migration.&lt;/p&gt;

&lt;p&gt;If historical interactions belong to &lt;code&gt;user_4812&lt;/code&gt;, the new ranking system should not suddenly know that same person as an unrelated identifier unless you maintain a deterministic mapping.&lt;/p&gt;

&lt;p&gt;The same principle applies to candidates.&lt;/p&gt;

&lt;p&gt;If your old system identifies a listing as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;listing_93882&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;preserve that identifier unless there is a strong architectural reason to change it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Define candidate generation explicitly
&lt;/h2&gt;

&lt;p&gt;A ranking API needs candidates.&lt;/p&gt;

&lt;p&gt;So before replacing Recommend, answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where will the candidate set come from?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Possible sources include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Algolia Search&lt;/li&gt;
&lt;li&gt;SQL queries&lt;/li&gt;
&lt;li&gt;vector retrieval&lt;/li&gt;
&lt;li&gt;category matching&lt;/li&gt;
&lt;li&gt;followed creators&lt;/li&gt;
&lt;li&gt;geographic filters&lt;/li&gt;
&lt;li&gt;recently active inventory&lt;/li&gt;
&lt;li&gt;editorial pools&lt;/li&gt;
&lt;li&gt;trending content&lt;/li&gt;
&lt;li&gt;business-specific retrieval systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where many migrations fail.&lt;/p&gt;

&lt;p&gt;The team removes the recommendation system and only later realizes the previous vendor was doing more candidate generation than expected.&lt;/p&gt;

&lt;p&gt;Document the retrieval contract clearly.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; user + current surface&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieval:&lt;/strong&gt; return up to 300 eligible posts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ranking:&lt;/strong&gt; score those 300&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final response:&lt;/strong&gt; return top 30&lt;/p&gt;

&lt;p&gt;That architecture is much easier to reason about and test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Apply hard eligibility before ranking
&lt;/h2&gt;

&lt;p&gt;Do not use ranking scores to enforce hard product constraints.&lt;/p&gt;

&lt;p&gt;Remove candidates that should never appear before calling the ranker.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blocked users&lt;/li&gt;
&lt;li&gt;unavailable products&lt;/li&gt;
&lt;li&gt;deleted content&lt;/li&gt;
&lt;li&gt;geographic restrictions&lt;/li&gt;
&lt;li&gt;privacy restrictions&lt;/li&gt;
&lt;li&gt;age restrictions&lt;/li&gt;
&lt;li&gt;moderation exclusions&lt;/li&gt;
&lt;li&gt;permission rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This follows the same principle described in &lt;a href="https://developers.google.com/machine-learning/recommendation/dnn/re-ranking" rel="noopener noreferrer"&gt;Google's recommendation re-ranking guidance&lt;/a&gt;, where final ordering can apply diversity, freshness, and other constraints after the core recommendation or scoring stage.&lt;/p&gt;

&lt;p&gt;The ranker should answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which eligible candidate is better?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It should not answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this candidate allowed to appear at all?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That distinction keeps policy logic deterministic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Map Algolia events into ranking signals
&lt;/h2&gt;

&lt;p&gt;Do not turn every positive interaction into a generic &lt;code&gt;engagement&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;Different actions express different levels of intent.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;view → weak signal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;click → moderate signal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;save → strong signal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;purchase → conversion&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hide → negative signal&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Algolia's own personalization guidance allows behavioral events to receive different weights because actions do not carry equal preference value. That same principle should survive the migration.&lt;/p&gt;

&lt;p&gt;Create an explicit event contract before backfilling.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Existing event&lt;/th&gt;
&lt;th&gt;New signal&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Product Viewed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;view&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Weak positive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Product Clicked&lt;/td&gt;
&lt;td&gt;&lt;code&gt;click&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Moderate positive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Added to Cart&lt;/td&gt;
&lt;td&gt;&lt;code&gt;high_intent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strong positive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Purchased&lt;/td&gt;
&lt;td&gt;&lt;code&gt;conversion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Outcome&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hidden&lt;/td&gt;
&lt;td&gt;&lt;code&gt;negative&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Explicit negative&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The schema is more important than the exact field names.&lt;/p&gt;

&lt;p&gt;What matters is preserving intent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Backfill historical data, then dual-write
&lt;/h2&gt;

&lt;p&gt;Before sending production ranking requests, backfill historical interactions.&lt;/p&gt;

&lt;p&gt;Validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;total event counts&lt;/li&gt;
&lt;li&gt;unique users&lt;/li&gt;
&lt;li&gt;unique candidates&lt;/li&gt;
&lt;li&gt;timestamp range&lt;/li&gt;
&lt;li&gt;event distribution&lt;/li&gt;
&lt;li&gt;missing identifiers&lt;/li&gt;
&lt;li&gt;duplicated events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then start &lt;strong&gt;dual-writing&lt;/strong&gt; new events.&lt;/p&gt;

&lt;p&gt;If a user clicks a result today, both the existing Algolia pipeline and the replacement ranking pipeline should receive that event during the transition period.&lt;/p&gt;

&lt;p&gt;Without dual-write, the systems drift apart.&lt;/p&gt;

&lt;p&gt;Algolia continues learning from fresh behavior while the new system evaluates stale history.&lt;/p&gt;

&lt;p&gt;That makes any ranking comparison unreliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Shadow the new ranking API
&lt;/h2&gt;

&lt;p&gt;Do not change what users see immediately.&lt;/p&gt;

&lt;p&gt;Send the same production candidate sets to both systems and record the replacement rankings without exposing them to users.&lt;/p&gt;

&lt;p&gt;Track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;top-10 overlap&lt;/li&gt;
&lt;li&gt;position changes&lt;/li&gt;
&lt;li&gt;missing candidates&lt;/li&gt;
&lt;li&gt;candidate counts&lt;/li&gt;
&lt;li&gt;empty responses&lt;/li&gt;
&lt;li&gt;p50 latency&lt;/li&gt;
&lt;li&gt;p95 latency&lt;/li&gt;
&lt;li&gt;p99 latency&lt;/li&gt;
&lt;li&gt;cold-start behavior&lt;/li&gt;
&lt;li&gt;diversity&lt;/li&gt;
&lt;li&gt;business-rule violations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not expect identical results.&lt;/p&gt;

&lt;p&gt;The purpose of shadow mode is to identify &lt;strong&gt;unexplained or harmful differences&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For teams moving toward a candidate-in, ranked-list-out architecture, the &lt;a href="https://gortex.ai/ranking-api/" rel="noopener noreferrer"&gt;Gortex Ranking API&lt;/a&gt; is one example of a decision layer that can sit after retrieval while candidate generation remains inside the application's existing stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Run a controlled A/B test
&lt;/h2&gt;

&lt;p&gt;Shadow testing verifies technical compatibility.&lt;/p&gt;

&lt;p&gt;It does not prove that the replacement ranking is better.&lt;/p&gt;

&lt;p&gt;Route a small portion of production traffic to the new path.&lt;/p&gt;

&lt;p&gt;A reasonable sequence might be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5% → 10% → 25% → 50% → 100%&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Measure actual product outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CTR&lt;/li&gt;
&lt;li&gt;conversion&lt;/li&gt;
&lt;li&gt;revenue per session&lt;/li&gt;
&lt;li&gt;watch time&lt;/li&gt;
&lt;li&gt;dwell time&lt;/li&gt;
&lt;li&gt;saves&lt;/li&gt;
&lt;li&gt;applications&lt;/li&gt;
&lt;li&gt;matches&lt;/li&gt;
&lt;li&gt;retention&lt;/li&gt;
&lt;li&gt;negative feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because offline ranking similarity does not tell you whether users prefer the new ordering.&lt;/p&gt;

&lt;p&gt;Algolia's own personalization guidance recommends validating personalization through experiments rather than assuming that a different ranking strategy automatically improves business outcomes.&lt;/p&gt;

&lt;p&gt;The winning system is the one that improves the metric your product actually cares about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10: Keep rollback available
&lt;/h2&gt;

&lt;p&gt;Do not delete the Algolia path as soon as the new system reaches 100% traffic.&lt;/p&gt;

&lt;p&gt;Keep the previous path behind a feature flag until the replacement has survived normal traffic, peak traffic, deployments, and provider failures.&lt;/p&gt;

&lt;p&gt;Define rollback conditions before launch.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;p99 latency exceeds target&lt;/li&gt;
&lt;li&gt;error rate increases&lt;/li&gt;
&lt;li&gt;candidate counts fall unexpectedly&lt;/li&gt;
&lt;li&gt;conversions decline&lt;/li&gt;
&lt;li&gt;event ingestion breaks&lt;/li&gt;
&lt;li&gt;diversity collapses&lt;/li&gt;
&lt;li&gt;eligibility rules are violated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your application should also have a vendor-independent fallback.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ranking API unavailable → cached ranking → freshness/popularity ordering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A ranking failure should reduce personalization quality.&lt;/p&gt;

&lt;p&gt;It should not take the feed offline.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you stay with Algolia Recommend?
&lt;/h2&gt;

&lt;p&gt;Migration is not automatically the right decision.&lt;/p&gt;

&lt;p&gt;Stay with Algolia Recommend if your primary use cases remain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Related Products&lt;/li&gt;
&lt;li&gt;Frequently Bought Together&lt;/li&gt;
&lt;li&gt;similar content&lt;/li&gt;
&lt;li&gt;trending items&lt;/li&gt;
&lt;li&gt;ecommerce cross-sell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and Algolia already owns most of your search, catalog, and behavioral infrastructure.&lt;/p&gt;

&lt;p&gt;Moving to a dedicated ranking API becomes more compelling when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your application already generates candidates&lt;/li&gt;
&lt;li&gt;final ordering is strategically important&lt;/li&gt;
&lt;li&gt;you rank non-product objects&lt;/li&gt;
&lt;li&gt;retrieval and ranking need separate release cycles&lt;/li&gt;
&lt;li&gt;multiple surfaces need the same ranking interface&lt;/li&gt;
&lt;li&gt;you want tighter control over rules and observability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;Migrating from Algolia Recommend to a ranking API is not an endpoint swap.&lt;/p&gt;

&lt;p&gt;It is an architectural shift from:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;recommendation system generates results&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;application generates candidates → ranking system decides order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The safest sequence is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;inventory → recover events → preserve identity → define retrieval → enforce eligibility → map signals → backfill → dual-write → shadow → A/B test → gradual cutover → rollback protection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most important thing you carry through the migration is not the old model.&lt;/p&gt;

&lt;p&gt;It is your &lt;strong&gt;behavioral history, identity mapping, eligibility rules, candidate-generation logic, and measurement framework&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Preserve those correctly, and replacing the ranking infrastructure becomes a controlled engineering project rather than a risky rewrite of your recommendation system.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Migrating From Amazon Personalize: Data Export, Schema Mapping, and Cutover</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Wed, 28 Oct 2026 18:16:39 +0000</pubDate>
      <link>https://dev.to/heminjoshi/migrating-from-amazon-personalize-data-export-schema-mapping-and-cutover-6go</link>
      <guid>https://dev.to/heminjoshi/migrating-from-amazon-personalize-data-export-schema-mapping-and-cutover-6go</guid>
      <description>&lt;p&gt;Migrating from Amazon Personalize is not primarily a model-replacement project.&lt;/p&gt;

&lt;p&gt;It is a &lt;strong&gt;data semantics and production cutover project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A team can successfully export millions of interactions and still end up with worse recommendations because event meanings changed, impressions disappeared, user or item IDs were remapped incorrectly, or the new ranking system started with incomplete real-time history.&lt;/p&gt;

&lt;p&gt;For engineering teams evaluating an Amazon Personalize alternative, the safest migration sequence is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory → Export → Validate → Map schemas → Backfill → Dual-write → Shadow → Gradual cutover → Retire&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most important rule is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Do not switch recommendation APIs until the new system receives the same behavioral truth as the old one.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What needs to move from Amazon Personalize?
&lt;/h2&gt;

&lt;p&gt;Most migrations need to account for three core Amazon Personalize dataset types:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;Important fields&lt;/th&gt;
&lt;th&gt;Migration purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Item interactions&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;USER_ID&lt;/code&gt;, &lt;code&gt;ITEM_ID&lt;/code&gt;, &lt;code&gt;TIMESTAMP&lt;/code&gt;, event data&lt;/td&gt;
&lt;td&gt;Behavioral history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Users&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;USER_ID&lt;/code&gt; + metadata&lt;/td&gt;
&lt;td&gt;User context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Items&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ITEM_ID&lt;/code&gt; + metadata&lt;/td&gt;
&lt;td&gt;Candidate attributes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The official &lt;a href="https://docs.aws.amazon.com/personalize/latest/dg/custom-datasets-and-schemas.html" rel="noopener noreferrer"&gt;Amazon Personalize custom dataset documentation&lt;/a&gt; requires &lt;code&gt;USER_ID&lt;/code&gt;, &lt;code&gt;ITEM_ID&lt;/code&gt;, and &lt;code&gt;TIMESTAMP&lt;/code&gt; for item interactions. Users and Items datasets use their respective IDs plus metadata fields.&lt;/p&gt;

&lt;p&gt;But these tables are only part of the migration.&lt;/p&gt;

&lt;p&gt;You also need to inventory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;event types&lt;/li&gt;
&lt;li&gt;event values&lt;/li&gt;
&lt;li&gt;impression data&lt;/li&gt;
&lt;li&gt;contextual fields&lt;/li&gt;
&lt;li&gt;filters&lt;/li&gt;
&lt;li&gt;promotions&lt;/li&gt;
&lt;li&gt;recipes&lt;/li&gt;
&lt;li&gt;campaigns or recommenders&lt;/li&gt;
&lt;li&gt;candidate-generation logic&lt;/li&gt;
&lt;li&gt;online event tracking&lt;/li&gt;
&lt;li&gt;business rules&lt;/li&gt;
&lt;li&gt;fallback behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trained Amazon Personalize model itself is not the portable asset.&lt;/p&gt;

&lt;p&gt;AWS's dataset export capability exports &lt;strong&gt;dataset records to Amazon S3&lt;/strong&gt;, so the practical migration unit is your data, event semantics, candidate logic, and production behavior rather than a transferable trained model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Export all Amazon Personalize data
&lt;/h2&gt;

&lt;p&gt;Amazon Personalize provides a dataset export job for sending dataset records to S3.&lt;/p&gt;

&lt;p&gt;The important detail is the &lt;strong&gt;ingestion mode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;AWS lets you export:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BULK&lt;/code&gt;: data imported through dataset import jobs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT&lt;/code&gt;: data added individually through APIs such as &lt;code&gt;PutEvents&lt;/code&gt;, &lt;code&gt;PutUsers&lt;/code&gt;, or &lt;code&gt;PutItems&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ALL&lt;/code&gt;: both sources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most production migrations, &lt;strong&gt;ALL is the safest choice&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Suppose you initially imported 30 million historical interactions six months ago.&lt;/p&gt;

&lt;p&gt;Since then, your application has continuously sent views, clicks, purchases, watches, or other interactions through &lt;code&gt;PutEvents&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Exporting only the original bulk dataset would produce a technically valid file that is missing months of behavioral history.&lt;/p&gt;

&lt;p&gt;AWS explicitly supports exporting both bulk and incremental records through its &lt;a href="https://docs.aws.amazon.com/personalize/latest/dg/create-dataset-export-job.html" rel="noopener noreferrer"&gt;dataset export jobs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before moving forward, validate:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Row counts:&lt;/strong&gt; Does the exported volume approximately match expectations?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time range:&lt;/strong&gt; Do the oldest and newest interaction timestamps look correct?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User coverage:&lt;/strong&gt; How many unique users appear?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Item coverage:&lt;/strong&gt; How many active items appear?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event distribution:&lt;/strong&gt; What percentage is view, click, purchase, like, watch, or another event?&lt;/p&gt;

&lt;p&gt;There is also an important limitation: AWS states that Actions and Action interactions datasets cannot be exported through the standard dataset export capability. Teams using those features should recover that history from their original event pipeline or another source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Preserve IDs before changing schemas
&lt;/h2&gt;

&lt;p&gt;Do not casually regenerate user or item IDs during migration.&lt;/p&gt;

&lt;p&gt;Amazon Personalize identifies interactions through &lt;code&gt;USER_ID&lt;/code&gt; and &lt;code&gt;ITEM_ID&lt;/code&gt;, both represented as strings.&lt;/p&gt;

&lt;p&gt;If:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;user_9182&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;becomes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;76412&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;in the new ranking system, that can be fine technically.&lt;/p&gt;

&lt;p&gt;But now every event pipeline, catalog record, experiment, recommendation log, and debugging workflow needs the same mapping.&lt;/p&gt;

&lt;p&gt;Unless there is a strong privacy or architectural reason to change IDs, preserve them.&lt;/p&gt;

&lt;p&gt;The migration becomes dramatically easier when:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;old USER_ID = new user_id&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;old ITEM_ID = new candidate_id&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a managed &lt;a href="https://gortex.ai/ranking-api/" rel="noopener noreferrer"&gt;ranking API such as Gortex&lt;/a&gt;, the equivalent item might not even be a traditional product. It could be a profile, job, creator, post, restaurant, or marketplace listing.&lt;/p&gt;

&lt;p&gt;The principle remains the same:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;preserve the identity of the candidate across systems.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Map event semantics, not just columns
&lt;/h2&gt;

&lt;p&gt;This is where many recommendation migrations go wrong.&lt;/p&gt;

&lt;p&gt;Amazon Personalize supports multiple interaction types such as clicks, watches, purchases, or custom events through &lt;code&gt;EVENT_TYPE&lt;/code&gt;. Its newer personalized-ranking recipes can also assign different weights to different event types.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;purchase&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;is not automatically equivalent to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;click&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;profile_view&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;may not mean the same thing as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;like&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;in the new system.&lt;/p&gt;

&lt;p&gt;Create a migration contract:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Amazon Personalize&lt;/th&gt;
&lt;th&gt;New system&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;USER_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;user_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stable user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ITEM_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;candidate_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rankable object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TIMESTAMP&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Event time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EVENT_TYPE=click&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;click&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Positive interaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EVENT_TYPE=purchase&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;conversion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strong outcome&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EVENT_VALUE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strength/value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;IMPRESSION&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;exposure list&lt;/td&gt;
&lt;td&gt;Items shown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do not collapse all positive interactions into a single generic "engagement" event unless you have tested the impact.&lt;/p&gt;

&lt;p&gt;A purchase, message, application, match, save, click, and impression can carry dramatically different intent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Do not lose impression data
&lt;/h2&gt;

&lt;p&gt;Clicks tell you what a user selected.&lt;/p&gt;

&lt;p&gt;They do not tell you what the user &lt;strong&gt;had the opportunity to select&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Amazon Personalize supports explicit impressions and can also derive implicit impressions when a &lt;code&gt;recommendationId&lt;/code&gt; is included with a &lt;code&gt;PutEvents&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;That information matters because otherwise:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;not clicked&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;can accidentally become:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;disliked&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;even when the candidate was never visible.&lt;/p&gt;

&lt;p&gt;When migrating, preserve where possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;recommendation ID&lt;/li&gt;
&lt;li&gt;items displayed&lt;/li&gt;
&lt;li&gt;displayed positions&lt;/li&gt;
&lt;li&gt;clicked item&lt;/li&gt;
&lt;li&gt;event timestamp&lt;/li&gt;
&lt;li&gt;surface&lt;/li&gt;
&lt;li&gt;session ID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This becomes especially important for feeds, dating apps, job boards, and marketplaces where position bias is strong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Rebuild user and item metadata deliberately
&lt;/h2&gt;

&lt;p&gt;Amazon Personalize supports up to &lt;strong&gt;25 user metadata fields&lt;/strong&gt; and up to &lt;strong&gt;100 item metadata fields&lt;/strong&gt; in custom schemas.&lt;/p&gt;

&lt;p&gt;Do not automatically migrate every field simply because it exists.&lt;/p&gt;

&lt;p&gt;For each feature ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does ranking actually use it?&lt;/li&gt;
&lt;li&gt;Is it still populated reliably?&lt;/li&gt;
&lt;li&gt;Is it available at serving time?&lt;/li&gt;
&lt;li&gt;Is it allowed under your privacy policies?&lt;/li&gt;
&lt;li&gt;Does the destination system understand it?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Amazon Personalize also supports &lt;code&gt;CREATION_TIMESTAMP&lt;/code&gt; for items, which can help models account for item age. That can translate into freshness features in the target ranking architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Backfill before sending live traffic
&lt;/h2&gt;

&lt;p&gt;Load historical interactions before enabling the new production endpoint.&lt;/p&gt;

&lt;p&gt;Then verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user count&lt;/li&gt;
&lt;li&gt;candidate count&lt;/li&gt;
&lt;li&gt;interaction count&lt;/li&gt;
&lt;li&gt;timestamp distribution&lt;/li&gt;
&lt;li&gt;event-type distribution&lt;/li&gt;
&lt;li&gt;metadata completeness&lt;/li&gt;
&lt;li&gt;missing IDs&lt;/li&gt;
&lt;li&gt;duplicate events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The new system should have enough historical context to produce meaningful rankings before it receives its first production request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Dual-write real-time events
&lt;/h2&gt;

&lt;p&gt;Do not cut Amazon Personalize event ingestion first.&lt;/p&gt;

&lt;p&gt;For a transition window, send new events to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon Personalize + new ranking system&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Amazon Personalize uses &lt;code&gt;PutEvents&lt;/code&gt; to continuously append real-time interactions and keep user behavior fresh.&lt;/p&gt;

&lt;p&gt;Your replacement needs the same continuity.&lt;/p&gt;

&lt;p&gt;Dual-writing prevents a dangerous scenario where the new system is tested using an increasingly stale snapshot while Personalize continues learning from current traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Shadow the new ranker
&lt;/h2&gt;

&lt;p&gt;Before changing what users see, send the same production candidates to both systems.&lt;/p&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;overlap in top results&lt;/li&gt;
&lt;li&gt;position changes&lt;/li&gt;
&lt;li&gt;candidate eligibility&lt;/li&gt;
&lt;li&gt;latency&lt;/li&gt;
&lt;li&gt;empty responses&lt;/li&gt;
&lt;li&gt;cold-start behavior&lt;/li&gt;
&lt;li&gt;diversity&lt;/li&gt;
&lt;li&gt;relevance&lt;/li&gt;
&lt;li&gt;business-rule compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not expect identical ordering.&lt;/p&gt;

&lt;p&gt;A migration exists partly because the systems work differently.&lt;/p&gt;

&lt;p&gt;The goal is to detect &lt;strong&gt;unexplained or harmful differences&lt;/strong&gt; before users experience them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Compare online outcomes, not only offline scores
&lt;/h2&gt;

&lt;p&gt;Amazon Personalize provides offline metrics for trained solution versions, but AWS specifically warns against comparing models trained on different datasets because metric differences may come from the data rather than the model.&lt;/p&gt;

&lt;p&gt;A vendor migration almost certainly changes both model and implementation.&lt;/p&gt;

&lt;p&gt;So the final test needs production outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CTR&lt;/li&gt;
&lt;li&gt;conversion&lt;/li&gt;
&lt;li&gt;dwell time&lt;/li&gt;
&lt;li&gt;completed purchase&lt;/li&gt;
&lt;li&gt;application rate&lt;/li&gt;
&lt;li&gt;match rate&lt;/li&gt;
&lt;li&gt;message rate&lt;/li&gt;
&lt;li&gt;retention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start with a small traffic cohort.&lt;/p&gt;

&lt;p&gt;Then increase traffic only when both product metrics and operational metrics remain healthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  A safe Amazon Personalize cutover sequence
&lt;/h2&gt;

&lt;p&gt;A practical rollout looks like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Export historical data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Validate schemas and event semantics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Backfill the new system&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Dual-write live events&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Shadow production requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Compare rankings and latency&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Send 5% to 10% of traffic to the new system&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Increase gradually&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Keep Amazon Personalize as fallback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Retire only after event and recommendation quality stabilize&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The safest migration is intentionally boring.&lt;/p&gt;

&lt;p&gt;There should never be one morning where Amazon Personalize is switched off and an untested ranker suddenly receives 100% of traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;Migrating from Amazon Personalize is not primarily about replacing an AWS API.&lt;/p&gt;

&lt;p&gt;It is about preserving the behavioral system that made personalization work.&lt;/p&gt;

&lt;p&gt;Export &lt;strong&gt;both historical and incrementally ingested data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Preserve stable user and candidate IDs.&lt;/p&gt;

&lt;p&gt;Map event meaning rather than blindly renaming columns.&lt;/p&gt;

&lt;p&gt;Keep impressions and exposure context.&lt;/p&gt;

&lt;p&gt;Dual-write live events.&lt;/p&gt;

&lt;p&gt;Shadow the new ranker.&lt;/p&gt;

&lt;p&gt;Cut traffic over gradually.&lt;/p&gt;

&lt;p&gt;Whether the destination is another recommendation engine or a broader decision layer such as the &lt;a href="https://gortex.ai/ranking-api/" rel="noopener noreferrer"&gt;Gortex Ranking API&lt;/a&gt;, the migration succeeds when the new system inherits enough context to make better decisions without disrupting the product.&lt;/p&gt;

&lt;p&gt;The question is not simply:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Can we export our Amazon Personalize data?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Can we preserve the meaning of our ranking system while changing the infrastructure underneath it?"&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>machinelearning</category>
      <category>tensorflow</category>
      <category>ai</category>
    </item>
    <item>
      <title>How Much Does a Recommendation API Cost at 20 Million Requests a Month?</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Mon, 26 Oct 2026 18:30:37 +0000</pubDate>
      <link>https://dev.to/heminjoshi/how-much-does-a-recommendation-api-cost-at-20-million-requests-a-month-47e5</link>
      <guid>https://dev.to/heminjoshi/how-much-does-a-recommendation-api-cost-at-20-million-requests-a-month-47e5</guid>
      <description>&lt;p&gt;Recommendation API cost is the recurring expense of generating or ranking suggested items through a hosted service. Total cost includes any billed inference, training, data processing, infrastructure, and operational work.&lt;/p&gt;

&lt;p&gt;Retrieval selects candidate items from a catalog. Ranking orders eligible candidates. Inference is the production calculation returning recommendations. An interaction is a recorded event, such as an impression, click, or purchase. Billing definitions vary by contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR: What should you budget?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;At 20 million monthly requests, every $0.05 per 1,000 requests adds $1,000 in monthly inference charges.&lt;/li&gt;
&lt;li&gt;At illustrative rates of $0.0556, $0.15, and $0.60 per thousand, monthly inference equals $1,112, $3,000, and $12,000 respectively.&lt;/li&gt;
&lt;li&gt;Training, interaction ingestion, minimum throughput, retrieval, and engineering ownership can change total costs substantially.&lt;/li&gt;
&lt;li&gt;A ranking-only API is not equivalent to a complete recommendation engine. Compare identical workloads and responsibilities.&lt;/li&gt;
&lt;li&gt;Evaluate cost per successful response and measured business outcome, not advertised request pricing alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How much do 20 million recommendation requests cost?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The answer is a formula, not a universal vendor price:&lt;/strong&gt; multiply billable requests by the contract's unit rate, then add fixed fees and separately billed components. Publicly documented inference tariffs use different rates for different model classes and plans, so one figure cannot represent the entire market.&lt;/p&gt;

&lt;p&gt;At 20 million requests, there are 20,000 units of one thousand calls. The table below is an arithmetic sensitivity analysis, not a list of vendor quotes or verified industry averages.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Assumed price per 1,000 calls&lt;/th&gt;
&lt;th&gt;Monthly inference cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;$0.025&lt;/td&gt;
&lt;td&gt;$500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.05&lt;/td&gt;
&lt;td&gt;$1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.10&lt;/td&gt;
&lt;td&gt;$2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.15&lt;/td&gt;
&lt;td&gt;$3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.30&lt;/td&gt;
&lt;td&gt;$6,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$0.60&lt;/td&gt;
&lt;td&gt;$12,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For example, &lt;code&gt;20,000,000 / 1,000 x $0.15 = $3,000&lt;/code&gt;. If a plan includes one million calls, subtract that allowance before applying the relevant tier. If it has a monthly platform minimum, add or compare that commitment as the contract specifies. Never add both without checking whether usage is already included.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a recommendation API actually bill for?
&lt;/h2&gt;

&lt;p&gt;A request may return ten items or one hundred items, yet some contracts bill per call. Others charge for recommendations generated, active users, item counts, or guaranteed throughput. Consequently, twenty million feed refreshes do not always equal twenty million billable transactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inference:&lt;/strong&gt; Real-time personalized responses, candidate scoring, or reranking. Separate billing can apply to batch jobs and online endpoints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training:&lt;/strong&gt; Model creation and retraining, sometimes measured by computation hours or interactions processed. A rules-based ranker might have no training charge, while an actively trained recommender has recurring model expenses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data:&lt;/strong&gt; Behavioral event ingestion, catalog updates, retained records, storage, and network transfer. A single feed request can produce multiple impression events plus later clicks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Capacity:&lt;/strong&gt; Reserved throughput, service minimums, regional deployment, and dedicated infrastructure. Billing floors can matter when traffic drops overnight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operations:&lt;/strong&gt; Monitoring, fallback responses, integration maintenance, incident handling, and experimentation remain real costs even when absent from a vendor invoice.&lt;/p&gt;

&lt;p&gt;A buyer should require a written definition of each billable unit and whether failed requests, retries, test environments, and metadata responses count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why can actual billed requests exceed 20 million?
&lt;/h2&gt;

&lt;p&gt;Consider a thirty-day month: twenty million requests average approximately 7.72 per second. Traffic, however, arrives unevenly. A platform that serves bursts of 100 requests per second may need higher reserved capacity despite its modest average.&lt;/p&gt;

&lt;p&gt;Now assume 5% of requests are retried once after a timeout. If each retry is billable, traffic increases from 20 million to 21 million calls. At $0.15 per thousand, inference rises from $3,000 to $3,150.&lt;/p&gt;

&lt;p&gt;Some managed deployments also bill a minimum transaction rate while an endpoint remains active. An active one-request-per-second floor corresponds to 2,592,000 monthly transactions over thirty days, although whether this creates incremental charges depends on hourly traffic and the vendor's precise billing rules.&lt;/p&gt;

&lt;p&gt;The correct forecast uses hourly request logs, not monthly totals alone. Include seasonality, experiments, duplicate requests, failure retries, and multiple recommendation surfaces.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do training and interaction events change the invoice?
&lt;/h2&gt;

&lt;p&gt;Assume a hypothetical service charges $0.05 per gigabyte ingested, $0.002 per thousand training interactions, and $0.15 per thousand inference requests. These are illustrative unit assumptions, not a consolidated vendor quote.&lt;/p&gt;

&lt;p&gt;With 200 GB uploaded, ten million interactions considered during each of eight training runs, and twenty million inference requests, the arithmetic is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data ingestion: 200 x $0.05 = $10.&lt;/li&gt;
&lt;li&gt;Model training: 80,000 units x $0.002 = $160.&lt;/li&gt;
&lt;li&gt;Inference: 20,000 units x $0.15 = $3,000.&lt;/li&gt;
&lt;li&gt;Total modeled service charges: &lt;strong&gt;$3,170 monthly&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This excludes retrieval, application hosting, support, storage beyond included allowances, and taxes. If the plan prices training by compute hours instead, the same calculation cannot be reused. Confirm whether historical events are charged again when retraining or only upon first ingestion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is ranking-only infrastructure cheaper than a complete recommender?
&lt;/h2&gt;

&lt;p&gt;It can be cheaper for a platform that already retrieves suitable candidates, but it is not inherently cheaper for every application. Full recommendation systems often handle candidate discovery, feature processing, model training, ranking, and serving. A ranking-only API assumes upstream retrieval exists and bills for ordering a supplied shortlist.&lt;/p&gt;

&lt;p&gt;This architectural separation matters because you should not purchase duplicate functionality. The &lt;a href="https://gortex.ai/blog/recommendation-engine-architecture" rel="noopener noreferrer"&gt;Gortex recommendation engine architecture guide&lt;/a&gt; explains how retrieval, ranking, and serving work together.&lt;/p&gt;

&lt;p&gt;For a social feed, existing follow-graph retrieval might already provide 200 eligible posts. The remaining problem is ordering those posts for a recipient. Conversely, a catalog application that needs to discover relevant products among millions still requires candidate generation. An ordering endpoint alone cannot solve that discovery problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does Gortex fit in this cost calculation?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://gortex.ai/ranking-api" rel="noopener noreferrer"&gt;Gortex's ranking API&lt;/a&gt; receives a recipient, context, and previously retrieved candidates through &lt;code&gt;POST /v1/decide&lt;/code&gt;. It returns an ordered result, supported sponsored placements, and decision identifiers. Its current scope includes calibrated linear ranking and deterministic sponsored-slot filling.&lt;/p&gt;

&lt;p&gt;Gortex is in private beta, and a public 20-million-request tariff is not verified. Therefore, assigning it a made-up dollar amount would be misleading. Its current ranking approach should not be presented as a trained personalized recommendation model, nor should its sponsored placement be confused with a live auction or campaign-management platform.&lt;/p&gt;

&lt;p&gt;The relevant cost question is whether one decisioning integration can replace separate application-side ordering and sponsored-placement logic. The &lt;a href="https://gortex.ai/blog/ranking-api-explained-how-to-choose-one" rel="noopener noreferrer"&gt;ranking API buyer's guide&lt;/a&gt; outlines latency, reliability, integration boundaries, and fallback considerations.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you compare API costs fairly?
&lt;/h2&gt;

&lt;p&gt;Use an identical test contract. Specify monthly call volume, peak requests per second, candidates per call, returned items, active users, events ingested, retraining cadence, and required regions. Compare the same features and success criteria rather than treating nominal request rates as interchangeable.&lt;/p&gt;

&lt;p&gt;Do not substitute monthly active users for requests without a measured calls-per-user ratio. For instance, 500,000 active users generating forty decisions each produce 20 million requests. A client that refreshes recommendations on every scroll may produce substantially more. Instrument distinct surfaces separately so product teams can see whether homepage carousels, search reranking, and notification feeds are responsible for additional billable traffic.&lt;/p&gt;

&lt;p&gt;Then calculate three measures: &lt;strong&gt;monthly total cost&lt;/strong&gt;, &lt;strong&gt;cost per thousand usable responses&lt;/strong&gt;, and &lt;strong&gt;cost per meaningful outcome&lt;/strong&gt;. A response is usable only if it satisfies availability, eligibility, freshness, and latency requirements.&lt;/p&gt;

&lt;p&gt;For example, suppose a hypothetical service costs $4,000 monthly and produces usable responses for 95% of twenty million calls. Cost per thousand usable responses is &lt;code&gt;$4,000 / 19,000,000 x 1,000&lt;/code&gt;, or approximately $0.211. The 95% figure is an assumption, not a reported reliability rate.&lt;/p&gt;

&lt;p&gt;Evaluate outcomes through controlled online tests. Research by Hidasi and Czapp on offline recommender evaluation warns that flawed historical tests can mislead comparisons. Offline ranking scores alone do not establish incremental conversions or retention.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hidden costs should engineering teams investigate?
&lt;/h2&gt;

&lt;p&gt;Feature storage, network egress, event pipelines, and search infrastructure can remain outside the recommendation invoice. Engineering effort also includes schema integration, privacy reviews, observability, incident response, and contract migration.&lt;/p&gt;

&lt;p&gt;Ask how the system behaves when a dependency is slow. A cached recommendation or deterministic eligible fallback may preserve the experience without requiring a second paid call. Gortex's &lt;a href="https://gortex.ai/blog/how-to-build-a-feed-ranking-system" rel="noopener noreferrer"&gt;feed ranking systems guide&lt;/a&gt; explains why batching, caching, and graceful degradation belong in the serving design.&lt;/p&gt;

&lt;p&gt;If a feed includes sponsored placements, include monetization-related implementation costs separately. The &lt;a href="https://gortex.ai/blog/marketplace-advertising" rel="noopener noreferrer"&gt;Gortex marketplace advertising guide&lt;/a&gt; explains placement rules and measurement without equating advertising revenue to recommendation quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should a buyer choose at 20 million requests?
&lt;/h2&gt;

&lt;p&gt;Choose the smallest architecture that satisfies actual product requirements and constraints. If discovery and retrieval are already reliable, assess ranking-only decisioning. If candidates must be found and personalized across a large catalog, budget for retrieval and training as well.&lt;/p&gt;

&lt;p&gt;Request itemized quotes under three traffic scenarios, then measure relevance, p99 latency, failures, and total ownership cost. The defensible answer is not a single market-average price: &lt;strong&gt;at twenty million calls, every $0.10 per thousand changes inference spending by $2,000 monthly&lt;/strong&gt;, before the rest of the system is considered.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Dating App Recommendation Engine Without an ML Team</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Tue, 20 Oct 2026 17:34:52 +0000</pubDate>
      <link>https://dev.to/heminjoshi/dating-app-recommendation-engine-without-an-ml-team-5253</link>
      <guid>https://dev.to/heminjoshi/dating-app-recommendation-engine-without-an-ml-team-5253</guid>
      <description>&lt;p&gt;A dating app can launch with simple profile ordering.&lt;/p&gt;

&lt;p&gt;Show nearby users. Prioritize recently active profiles. Add a few preference filters. Maybe introduce some randomness.&lt;/p&gt;

&lt;p&gt;That works until the candidate pool grows and every user starts seeing a different quality of experience.&lt;/p&gt;

&lt;p&gt;At that point, the product needs to answer a harder question:&lt;/p&gt;

&lt;p&gt;Given 100 eligible profiles, which 20 should this user see first?&lt;/p&gt;

&lt;p&gt;For a dating app without an ML team, the best answer is usually not to build a recommendation engine from scratch.&lt;/p&gt;

&lt;p&gt;Instead, keep eligibility and safety rules inside your application, then send the eligible candidate set to a managed &lt;a href="https://gortex.ai/recommendation-engine-api/" rel="noopener noreferrer"&gt;recommendation engine API&lt;/a&gt; or ranking API for personalized ordering.&lt;/p&gt;

&lt;p&gt;For most teams today, Recombee is the strongest ready-to-use option for user-to-user recommendation, Amazon Personalize is attractive for AWS-heavy teams, Algolia can work when search and discovery are already part of the stack, and Gortex is an emerging option for &lt;a href="https://gortex.ai/dating-apps/" rel="noopener noreferrer"&gt;dating apps&lt;/a&gt; that want candidate reranking and a broader decision layer without building ranking infrastructure internally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short answer
&lt;/h2&gt;

&lt;p&gt;A dating app without an ML team should use this architecture:&lt;/p&gt;

&lt;p&gt;Hard eligibility filters → candidate retrieval → personalized profile ranking → product constraints → final feed&lt;/p&gt;

&lt;p&gt;Do not ask the ML system to decide who is legally, safely, or product-policy eligible.&lt;/p&gt;

&lt;p&gt;Your application should first handle constraints such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;age and location eligibility&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;gender and preference compatibility&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;blocked users&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;already rejected profiles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;moderation and safety exclusions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;inactive or unavailable accounts&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ranking layer should answer a narrower question:&lt;/p&gt;

&lt;p&gt;Among the profiles this user is allowed to see, which ones should appear first?&lt;/p&gt;

&lt;p&gt;That separation makes the system easier to control, debug, and replace later. It is the same boundary used in any &lt;a href="https://gortex.ai/feed-ranking-api/" rel="noopener noreferrer"&gt;feed ranking&lt;/a&gt; system: retrieval decides what is possible, ranking decides the order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a dating app should not start by building ML
&lt;/h2&gt;

&lt;p&gt;A basic ranking formula is easy to create:&lt;/p&gt;

&lt;p&gt;score = activity + distance + profile quality + affinity&lt;/p&gt;

&lt;p&gt;The difficult part starts afterward.&lt;/p&gt;

&lt;p&gt;A production recommendation system eventually needs interaction collection, feature pipelines, cold-start logic, retraining, online inference, monitoring, experiments, fallbacks, and methods for preventing feedback loops.&lt;/p&gt;

&lt;p&gt;A dating app also has a sparse-data problem.&lt;/p&gt;

&lt;p&gt;A new user has no swipe history. A newly created profile has little exposure. Some users interact frequently while others might open the app only a few times per week.&lt;/p&gt;

&lt;p&gt;That makes profile ranking an unusually poor place for a small product team to spend six months building infrastructure before it has proven what signals actually matter.&lt;/p&gt;

&lt;p&gt;A managed &lt;a href="https://gortex.ai/personalization-api/" rel="noopener noreferrer"&gt;personalization API&lt;/a&gt; lets the team collect real behavior first and gradually improve the ranking system.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Recombee: Best current fit for user-to-user recommendations
&lt;/h2&gt;

&lt;p&gt;For a dating app with no ML team, Recombee is probably the first platform I would evaluate.&lt;/p&gt;

&lt;p&gt;The reason is unusually specific to this use case.&lt;/p&gt;

&lt;p&gt;Recombee supports not only item recommendations but also user-to-user recommendations. Its &lt;a href="https://docs.recombee.com/api/recommendations" rel="noopener noreferrer"&gt;Recommend Users to User endpoint&lt;/a&gt; returns users similar to a given user based on interaction history and user properties.&lt;/p&gt;

&lt;p&gt;That maps naturally onto dating.&lt;/p&gt;

&lt;p&gt;Instead of pretending every profile is a product in a catalog, your application can work with users directly.&lt;/p&gt;

&lt;p&gt;Recombee also supports filtering and boosting through its &lt;a href="https://docs.recombee.com/reql" rel="noopener noreferrer"&gt;ReQL language&lt;/a&gt;. Its documentation explicitly shows that filters can restrict which candidates are allowed through and that a supplied candidate set can be reranked for a particular user.&lt;/p&gt;

&lt;p&gt;A dating app could therefore retrieve eligible profiles first and use ranking rules around attributes or context without training its own ranking model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.recombee.com/" rel="noopener noreferrer"&gt;Recombee&lt;/a&gt; currently states that its recommendation API responds in less than 200 ms and updates recommendations following user actions in real time. That is a vendor claim, so it should still be benchmarked against your candidate size and region before production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best for
&lt;/h3&gt;

&lt;p&gt;Teams that want the closest thing to a ready-made dating recommendation engine without hiring an ML team.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Amazon Personalize: Best for AWS-heavy teams
&lt;/h2&gt;

&lt;p&gt;Amazon Personalize is another credible choice, particularly if most of your data infrastructure already lives in AWS.&lt;/p&gt;

&lt;p&gt;Its &lt;a href="https://docs.aws.amazon.com/personalize/latest/dg/rankings.html" rel="noopener noreferrer"&gt;personalized-ranking workflow&lt;/a&gt; accepts a list of candidate items and reorders those candidates for a specific user. AWS also supports &lt;a href="https://docs.aws.amazon.com/personalize/latest/dg/get-personalized-rankings-sdk.html" rel="noopener noreferrer"&gt;contextual metadata and filters&lt;/a&gt; when requesting rankings.&lt;/p&gt;

&lt;p&gt;For a dating app, profiles could be represented as rankable items.&lt;/p&gt;

&lt;p&gt;Your application would still determine the eligible profile IDs:&lt;/p&gt;

&lt;p&gt;User request → eligibility service → 200 candidate profiles → Amazon Personalize → ranked profiles&lt;/p&gt;

&lt;p&gt;Amazon Personalize can also incorporate &lt;a href="https://docs.aws.amazon.com/personalize/latest/dg/recording-events.html" rel="noopener noreferrer"&gt;recent behavioral events&lt;/a&gt; into supported real-time personalization workflows, which makes it more useful than a purely batch-trained recommender.&lt;/p&gt;

&lt;p&gt;The tradeoff is operational complexity.&lt;/p&gt;

&lt;p&gt;You are adopting an AWS service with datasets, recipes, campaigns or recommenders, event ingestion, filters, and AWS-specific infrastructure.&lt;/p&gt;

&lt;p&gt;That may be perfectly reasonable for a team already using AWS heavily.&lt;/p&gt;

&lt;p&gt;It may feel excessive for a six-person startup that simply needs a better swipe deck.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best for
&lt;/h3&gt;

&lt;p&gt;AWS-native engineering teams comfortable managing more recommendation infrastructure themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Algolia: Better when discovery includes search
&lt;/h2&gt;

&lt;p&gt;Algolia is strong at search and discovery, and it also supports personalization and personalized recommendations.&lt;/p&gt;

&lt;p&gt;Algolia builds &lt;a href="https://www.algolia.com/doc/guides/personalization/advanced-personalization/what-is-advanced-personalization/concepts/user-profiles" rel="noopener noreferrer"&gt;user affinity profiles&lt;/a&gt; from behavioral events and can use those affinities to personalize results. Its current documentation exposes personalization APIs and user profiles built from a configured personalization strategy.&lt;/p&gt;

&lt;p&gt;That can work for dating products with searchable discovery experiences.&lt;/p&gt;

&lt;p&gt;For example, a platform that lets users explore communities, interests, locations, or profile categories may already have a reason to use Algolia.&lt;/p&gt;

&lt;p&gt;For a pure swipe feed, however, Algolia is less obviously matched to the problem than a system designed specifically around user or candidate recommendations.&lt;/p&gt;

&lt;p&gt;Search asks:&lt;/p&gt;

&lt;p&gt;What best matches this query?&lt;/p&gt;

&lt;p&gt;A dating feed often has no query.&lt;/p&gt;

&lt;p&gt;It asks:&lt;/p&gt;

&lt;p&gt;Who should this user see next?&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best for
&lt;/h3&gt;

&lt;p&gt;Dating products where profile discovery, filters, search, and personalized ranking are part of the same broader discovery experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Gortex: Emerging option when you already own candidate retrieval
&lt;/h2&gt;

&lt;p&gt;A newer architecture is to keep all candidate generation inside the dating app and use an external API only for the final decision.&lt;/p&gt;

&lt;p&gt;That is where Gortex is positioning its &lt;a href="https://gortex.ai/" rel="noopener noreferrer"&gt;ranking API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Gortex accepts a recipient, context, and candidate set, including profiles, and returns their order through one &lt;a href="https://gortex.ai/anatomy" rel="noopener noreferrer"&gt;/v1/decide request&lt;/a&gt;. Its &lt;a href="https://gortex.ai/dating-apps/" rel="noopener noreferrer"&gt;dating apps page&lt;/a&gt; lists dating among its target surfaces and states a sub-200 ms p99 target.&lt;/p&gt;

&lt;p&gt;The important caveat is maturity.&lt;/p&gt;

&lt;p&gt;Gortex is currently in private beta and its published architecture uses calibrated linear ranking today. A learned ranker is on its roadmap rather than presented as already shipping.&lt;/p&gt;

&lt;p&gt;So if the requirement is mature learned recommendations immediately, Recombee or Amazon Personalize is easier to defend today.&lt;/p&gt;

&lt;p&gt;Gortex becomes more interesting when the team wants to keep retrieval and hard constraints in-house, outsource the ordering layer, preserve &lt;a href="https://gortex.ai/anatomy" rel="noopener noreferrer"&gt;decision traces&lt;/a&gt;, and potentially add &lt;a href="https://gortex.ai/sponsored-listings-api/" rel="noopener noreferrer"&gt;sponsored placements&lt;/a&gt; to other discovery surfaces later.&lt;/p&gt;

&lt;p&gt;That is a different buying decision from adopting a full recommendation engine. The &lt;a href="https://gortex.ai/ladder" rel="noopener noreferrer"&gt;integration ladder&lt;/a&gt; shows how that starts with a single REST call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What signals should a dating profile ranker use?
&lt;/h2&gt;

&lt;p&gt;Do not begin with dozens of features.&lt;/p&gt;

&lt;p&gt;Start with signals tied closely to observed product behavior.&lt;/p&gt;

&lt;p&gt;Useful inputs might include:&lt;/p&gt;

&lt;p&gt;Explicit preference: Did the user state an interest in this type of profile?&lt;/p&gt;

&lt;p&gt;Behavioral affinity: What kinds of profiles has the user meaningfully engaged with?&lt;/p&gt;

&lt;p&gt;Recency: Is the candidate currently active?&lt;/p&gt;

&lt;p&gt;Distance or geography: How strongly should physical distance affect ordering?&lt;/p&gt;

&lt;p&gt;Profile quality: Does the profile contain enough information to make a useful decision?&lt;/p&gt;

&lt;p&gt;Exposure history: Has this user already seen the candidate repeatedly?&lt;/p&gt;

&lt;p&gt;Session behavior: Has the user's behavior changed during the current session?&lt;/p&gt;

&lt;p&gt;Then measure downstream outcomes.&lt;/p&gt;

&lt;p&gt;A swipe is useful, but it is not necessarily success.&lt;/p&gt;

&lt;p&gt;Depending on the product, better metrics might include:&lt;/p&gt;

&lt;p&gt;mutual match → conversation started → meaningful reply → retained user&lt;/p&gt;

&lt;p&gt;That prevents the ranking system from optimizing for superficial activity while degrading actual match quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about cold start?
&lt;/h2&gt;

&lt;p&gt;Cold start should influence your vendor choice.&lt;/p&gt;

&lt;p&gt;Recombee's &lt;a href="https://docs.recombee.com/logics" rel="noopener noreferrer"&gt;universal models&lt;/a&gt; combine collaborative and content-based approaches with popularity-based fallback behavior when data is sparse.&lt;/p&gt;

&lt;p&gt;But no API can invent intent that has never been expressed.&lt;/p&gt;

&lt;p&gt;A new dating user should therefore provide some initial signal through onboarding.&lt;/p&gt;

&lt;p&gt;That might be preferred distance, interests, relationship intent, languages, or other product-appropriate attributes.&lt;/p&gt;

&lt;p&gt;Then let behavior gradually replace assumptions.&lt;/p&gt;

&lt;p&gt;Do not wait until you have months of interaction history before personalizing.&lt;/p&gt;

&lt;p&gt;Equally, do not pretend the first ranking is deeply personalized when you know almost nothing about the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would choose
&lt;/h2&gt;

&lt;p&gt;For a dating app with no ML team, I would make the decision this way:&lt;/p&gt;

&lt;p&gt;Choose Recombee if you want the strongest ready-made fit for user-to-user recommendations and flexible filtering.&lt;/p&gt;

&lt;p&gt;Choose Amazon Personalize if your company already operates heavily on AWS and is comfortable with its recommendation workflow.&lt;/p&gt;

&lt;p&gt;Choose Algolia if profile search and discovery are already central to the product.&lt;/p&gt;

&lt;p&gt;Evaluate Gortex if you already control candidate retrieval and want an emerging ranking layer rather than another end-to-end recommendation stack.&lt;/p&gt;

&lt;p&gt;Most importantly, do not outsource hard eligibility and safety logic to the ranker.&lt;/p&gt;

&lt;p&gt;Let your application determine who can be shown.&lt;/p&gt;

&lt;p&gt;Let the ranking system determine who should be shown first.&lt;/p&gt;

&lt;p&gt;That boundary is the most important architectural decision a dating app without an ML team can get right.&lt;/p&gt;

&lt;p&gt;If you already own retrieval and want to see how the ordering layer works on your own candidate set, start with &lt;a href="https://gortex.ai/dating-apps/" rel="noopener noreferrer"&gt;Gortex for dating apps&lt;/a&gt; or try the &lt;a href="https://gortex.ai/simulation/" rel="noopener noreferrer"&gt;ranking simulation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>api</category>
      <category>softwareengineering</category>
      <category>startup</category>
    </item>
    <item>
      <title>How to Replace a Rules-Based Feed Ranker Without Rebuilding Your Feed</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Fri, 16 Oct 2026 14:27:33 +0000</pubDate>
      <link>https://dev.to/heminjoshi/how-to-replace-a-rules-based-feed-ranker-without-rebuilding-your-feed-2m8m</link>
      <guid>https://dev.to/heminjoshi/how-to-replace-a-rules-based-feed-ranker-without-rebuilding-your-feed-2m8m</guid>
      <description>&lt;p&gt;&lt;strong&gt;Rules-based feed ranker:&lt;/strong&gt; a ranking stage that orders feed items with hand-written logic, such as "boost followed authors, then sort by recency," instead of a scoring model trained on engagement data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Candidate generation:&lt;/strong&gt; the stage that retrieves the eligible items for one user. It decides what can appear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ranking layer:&lt;/strong&gt; the stage that orders those candidates. It decides what appears first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow mode:&lt;/strong&gt; running a new ranker on live requests while users still see the old ranker's output. The new ranker only produces logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interleaving:&lt;/strong&gt; an online test that merges two rankers' results into one list and credits each click to the ranker that contributed the item.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overlap@k:&lt;/strong&gt; the share of items that two rankers both place in their top k positions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The ranker is one stage of a feed pipeline. Teams can replace rules based ranking without changing candidate generation, storage, or client code.&lt;/li&gt;
&lt;li&gt;The migration has five steps: isolate the ranking call, convert rules into features or constraints, run shadow mode, test on live users, and cut over with a kill switch.&lt;/li&gt;
&lt;li&gt;Shadow mode compares both rankers on real traffic with zero user exposure.&lt;/li&gt;
&lt;li&gt;Policy rules, such as "never show blocked users," stay as hard filters outside the new ranker.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why can a feed ranker be replaced without rebuilding the feed?
&lt;/h2&gt;

&lt;p&gt;A feed ranker can be replaced in isolation because ranking is a stage boundary. The ranker receives a user, a surface, and a candidate list, and it returns the same candidates in a new order. If the new ranker accepts the same input and returns the same output shape, nothing upstream or downstream has to change.&lt;/p&gt;

&lt;p&gt;Most feed pipelines have four stages: candidate generation, filtering, ranking, and rendering. The migration below changes one function call and its configuration.&lt;/p&gt;

&lt;p&gt;One exception applies. If the current ranker is also the retrieval step, for example a SQL query with &lt;code&gt;ORDER BY&lt;/code&gt; and &lt;code&gt;LIMIT 20&lt;/code&gt;, the candidate set must be widened first. The section on edge cases covers this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: How do you isolate the ranking call?
&lt;/h2&gt;

&lt;p&gt;Isolation means every ranking decision passes through one function with a fixed signature: &lt;code&gt;rank(user, surface, candidates) -&amp;gt; ordered candidates&lt;/code&gt;. Nothing else in the codebase reorders items after this call.&lt;/p&gt;

&lt;p&gt;Find every place that sorts candidates after retrieval: SQL &lt;code&gt;ORDER BY&lt;/code&gt; clauses, sort calls in API handlers, and client-side re-sorting. Move that logic into the single function. Then add one configuration flag with three values: &lt;code&gt;rules&lt;/code&gt;, &lt;code&gt;shadow&lt;/code&gt;, and &lt;code&gt;new&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Step 1 is complete when the feed output is byte-identical to production and all existing tests pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: What happens to the existing rules?
&lt;/h2&gt;

&lt;p&gt;Each existing rule becomes either a feature that the new ranker can weigh or a hard constraint applied outside the ranker. Rule #7 in Google's &lt;a href="https://developers.google.com/machine-learning/guides/rules-of-ml" rel="noopener noreferrer"&gt;Rules of Machine Learning&lt;/a&gt; by Martin Zinkevich gives the same instruction: turn heuristics into features, or handle them externally.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Existing rule&lt;/th&gt;
&lt;th&gt;What it becomes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Boost posts from followed accounts&lt;/td&gt;
&lt;td&gt;Feature: &lt;code&gt;is_followed&lt;/code&gt; (0 or 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show newer posts first&lt;/td&gt;
&lt;td&gt;Feature: item age in hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Never show blocked or muted users&lt;/td&gt;
&lt;td&gt;Hard filter before ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max 2 posts per author in the top 10&lt;/td&gt;
&lt;td&gt;Diversity constraint after ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pin announcements to slot 1&lt;/td&gt;
&lt;td&gt;Fixed placement after ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A preference becomes a feature, because a model may learn to weigh it differently. A policy becomes a constraint, because no ranker should be able to violate legal, safety, or contractual rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: How do you run a new ranker in shadow mode?
&lt;/h2&gt;

&lt;p&gt;Shadow mode ranking calls the new ranker asynchronously on each request, logs its output next to the served output, and never shows it to users. The served response keeps the rules-based order, so a failure in the new ranker cannot affect the feed.&lt;/p&gt;

&lt;p&gt;The harness below runs with the Python standard library. Replace &lt;code&gt;new_ranker&lt;/code&gt; with the call to your model or vendor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;concurrent.futures&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ThreadPoolExecutor&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rules_ranker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Current production logic: followed authors first, then newest.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;follows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                  &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new_ranker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Stand-in. Replace with your model or HTTP client.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;overlap_at_k&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mean_rank_shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;shadow_compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;served&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;shadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;new_ranker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shadow_error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;)}))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shadow_compare&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latency_ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;overlap_at_k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;overlap_at_k&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;served&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mean_rank_shift&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mean_rank_shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;served&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rank_feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;served&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;rules_ranker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shadow_compare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;served&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;served&lt;/span&gt;  &lt;span class="c1"&gt;# users always see the rules-based order
&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;u1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;follows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
    &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;p&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="nf"&gt;rank_feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Log four signals per request: overlap@10, mean rank shift, latency, and error rate. An overlap@10 near 1.0 means the new ranker barely changes the feed. An overlap@10 near 0 means a large change, so sample those requests and review the lists by hand. Run shadow mode for at least one full week. Ron Kohavi, Diane Tang, and Ya Xu recommend full-week durations in &lt;a href="https://www.cambridge.org/core/books/trustworthy-online-controlled-experiments/D97B26382EB0EB2DC2019A7A7B518F59" rel="noopener noreferrer"&gt;Trustworthy Online Controlled Experiments&lt;/a&gt; (Cambridge University Press, 2020) because behavior varies by day of week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: How do you test the new ranker on live users?
&lt;/h2&gt;

&lt;p&gt;A live test exposes a small share of users to the new ranker and measures engagement against the rules-based baseline. Two methods work: an A/B test, which splits users between rankers, and interleaving, which mixes both rankers into one list for each user.&lt;/p&gt;

&lt;p&gt;Interleaving needs less traffic. Chapelle, Joachims, Radlinski, and Yue found interleaved comparisons more sensitive than standard A/B metrics in a large-scale search study (&lt;a href="https://dl.acm.org/doi/10.1145/2094072.2094078" rel="noopener noreferrer"&gt;ACM Transactions on Information Systems, 2012&lt;/a&gt;). A/B tests are still needed for session length and retention.&lt;/p&gt;

&lt;p&gt;Define guardrail metrics before the test starts. For feeds, useful guardrails are the hide or report rate, the share of creators receiving impressions, and p99 latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: How do you cut over safely?
&lt;/h2&gt;

&lt;p&gt;Cut over by ramping traffic in stages, for example 1%, 10%, 50%, then 100%, while keeping the rules ranker as an automatic fallback. If the new ranker errors or exceeds the latency budget, the service serves the rules-based order for that request.&lt;/p&gt;

&lt;p&gt;Keep the fallback path in production for at least one release cycle after reaching 100%.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is this approach the wrong choice?
&lt;/h2&gt;

&lt;p&gt;Stage-by-stage replacement fails in four situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ranking happens inside retrieval.&lt;/strong&gt; A query that returns 20 sorted rows gives a new ranker nothing to reorder. Widen candidate generation to a few hundred items first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No interaction logging exists.&lt;/strong&gt; Every learned or calibrated ranker needs impression and click data. Add logging before Step 3.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic is very low.&lt;/strong&gt; Online tests may not reach significance. Rely on shadow mode and manual list review instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The rules encode policy.&lt;/strong&gt; Those rules stay as constraints permanently, as Step 2 describes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where does a ranking API fit in this migration?
&lt;/h2&gt;

&lt;p&gt;A hosted ranking API replaces only the &lt;code&gt;new_ranker&lt;/code&gt; function. Steps 1, 2, 4, and 5 stay the same, which is why the shadow harness doubles as a vendor evaluation tool: each candidate vendor can run on real traffic before any contract.&lt;/p&gt;

&lt;p&gt;Gortex is one option for that slot, currently in invite-only beta. One request with a recipient, a surface, and a candidate set returns the ranked order and fills sponsored slots in the same response, at sub-200ms p99. Calibrated linear ranking and deterministic slot-filling ship today. A learned ranker is planned for mid-2027 and a real-time auction for Q1 2027. Details are on the Gortex &lt;a href="https://gortex.ai/feed-ranking-api" rel="noopener noreferrer"&gt;feed ranking API&lt;/a&gt; page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get a free feed teardown
&lt;/h2&gt;

&lt;p&gt;Send your current ranking rules and feed surface, and the Gortex team will map which rules become features, which stay as constraints, and what a shadow test should measure. Request access at &lt;a href="https://gortex.ai" rel="noopener noreferrer"&gt;gortex.ai&lt;/a&gt;, or book a demo with the founder at &lt;a href="mailto:h@gortex.ai"&gt;h@gortex.ai&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How long does it take to replace a rules-based ranker?&lt;/strong&gt;&lt;br&gt;
Isolation and rule mapping usually fit in one sprint. Shadow mode runs at least one full week, and the live test runs until it reaches significance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does replacing a rules-based ranker require a data science team?&lt;/strong&gt;&lt;br&gt;
No. Shadow mode, guardrails, and staged rollout are backend engineering tasks. A team needs modeling skills only if it trains its own ranker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can some rules stay after the migration?&lt;/strong&gt;&lt;br&gt;
Yes. Policy rules stay as filters or placement constraints. Only preference rules move into the ranker as features.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>10 Ranking Algorithms Used in Production: From Rules to Learning-to-Rank</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Tue, 13 Oct 2026 08:22:24 +0000</pubDate>
      <link>https://dev.to/heminjoshi/10-ranking-algorithms-used-in-production-from-rules-to-learning-to-rank-2fbe</link>
      <guid>https://dev.to/heminjoshi/10-ranking-algorithms-used-in-production-from-rules-to-learning-to-rank-2fbe</guid>
      <description>&lt;p&gt;Most ranking systems do not begin with machine learning.&lt;/p&gt;

&lt;p&gt;They begin with something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;score = freshness + popularity&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then the product grows. Users behave differently. Inventory expands. Cold start matters. Business rules accumulate. Personalization becomes important. Monetization enters the same surface.&lt;/p&gt;

&lt;p&gt;Eventually, one hand-tuned score is no longer enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short answer:&lt;/strong&gt; production ranking systems usually combine multiple approaches rather than rely on a single algorithm. A cheap model or heuristic narrows and scores candidates first, then more expensive models or reranking logic improve the final order.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://research.google/pubs/deep-neural-networks-for-youtube-recommendations/" rel="noopener noreferrer"&gt;Google's published YouTube architecture&lt;/a&gt; separates candidate generation from a dedicated deep ranking model. LinkedIn describes first-pass rankers feeding a second-pass ranker, followed by reranking. Vespa explicitly supports first-phase, second-phase, and global ranking so expensive models only run on the strongest candidates. &lt;/p&gt;

&lt;p&gt;That distinction matters if you are designing a feed, marketplace, recommendation system, job board, dating app, or discovery product.&lt;/p&gt;

&lt;p&gt;Here are 10 ranking algorithms and approaches commonly found in production systems, from deterministic rules to learned ranking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ranking algorithms at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Best suited for&lt;/th&gt;
&lt;th&gt;Personalization&lt;/th&gt;
&lt;th&gt;Complexity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rule-based ranking&lt;/td&gt;
&lt;td&gt;Policy and simple products&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weighted linear scoring&lt;/td&gt;
&lt;td&gt;Early production ranking&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Popularity and trending&lt;/td&gt;
&lt;td&gt;Cold start and discovery&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BM25&lt;/td&gt;
&lt;td&gt;Search relevance&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-based ranking&lt;/td&gt;
&lt;td&gt;Sparse interaction data&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collaborative filtering&lt;/td&gt;
&lt;td&gt;Behavioral recommendations&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Matrix factorization&lt;/td&gt;
&lt;td&gt;User-item affinity&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gradient-boosted trees&lt;/td&gt;
&lt;td&gt;Structured ranking features&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deep neural ranking&lt;/td&gt;
&lt;td&gt;Large, complex datasets&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning-to-rank&lt;/td&gt;
&lt;td&gt;Optimizing ordered results&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The useful question is not which algorithm is "best."&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;which ranking architecture matches your data, latency budget, product maturity, and objective&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you are still separating retrieval from ranking, our &lt;a href="https://gortex.ai/blog/ranking-api-explained-how-to-choose-one" rel="noopener noreferrer"&gt;Ranking API buyer's guide&lt;/a&gt; explains where the ranking layer sits in the request path.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Rule-Based Ranking
&lt;/h2&gt;

&lt;p&gt;Rule-based ranking is the simplest production approach.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;newest items first&lt;/li&gt;
&lt;li&gt;exclude unavailable inventory&lt;/li&gt;
&lt;li&gt;boost verified sellers&lt;/li&gt;
&lt;li&gt;cap posts from the same creator&lt;/li&gt;
&lt;li&gt;prioritize items within a user's geography&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rules are deterministic and easy to explain. That makes them extremely useful for hard constraints, even inside sophisticated ML systems.&lt;/p&gt;

&lt;p&gt;The mistake is using rules for everything.&lt;/p&gt;

&lt;p&gt;As more requirements appear, teams often end up with dozens of interacting conditions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if premium_user &amp;amp;&amp;amp; recent_item &amp;amp;&amp;amp; category_match &amp;amp;&amp;amp; seller_score &amp;gt; X...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Eventually, nobody can confidently predict how changing one weight affects the whole system.&lt;/p&gt;

&lt;p&gt;Rules work best for eligibility, safety, compliance, and non-negotiable product constraints. Learned systems work better when the question becomes "which eligible item is most valuable to this user?"&lt;/p&gt;

&lt;p&gt;That distinction is also central to how a modern &lt;a href="https://gortex.ai/decision-engine" rel="noopener noreferrer"&gt;decision engine&lt;/a&gt; separates policy from downstream ranking.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Weighted Linear Scoring
&lt;/h2&gt;

&lt;p&gt;Weighted scoring is often the first real ranking engine a startup builds.&lt;/p&gt;

&lt;p&gt;A simplified score might look like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;score = 0.40 relevance + 0.25 freshness + 0.20 popularity + 0.15 quality&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Unlike a single sort field, this combines multiple signals while remaining fast and explainable.&lt;/p&gt;

&lt;p&gt;Production search systems use the same basic idea. Vespa's documentation, for example, shows ranking expressions combining BM25 relevance with popularity and supports arbitrary mathematical combinations of document, query, and computed ranking features. &lt;/p&gt;

&lt;p&gt;Weighted scoring works particularly well when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the number of signals is manageable&lt;/li&gt;
&lt;li&gt;engineers understand their relative importance&lt;/li&gt;
&lt;li&gt;training data is limited&lt;/li&gt;
&lt;li&gt;explainability matters&lt;/li&gt;
&lt;li&gt;latency needs to remain predictable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The weakness is manual calibration. As the product evolves, someone has to decide whether freshness should be 0.25 or 0.31.&lt;/p&gt;

&lt;p&gt;Gortex currently takes this transparent approach with &lt;a href="https://gortex.ai/ranking-api" rel="noopener noreferrer"&gt;calibrated linear ranking&lt;/a&gt; in its private beta. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Popularity and Trending Ranking
&lt;/h2&gt;

&lt;p&gt;Popularity ranking orders items using aggregate behavior such as views, clicks, purchases, saves, or interactions.&lt;/p&gt;

&lt;p&gt;It is simple, but extremely useful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/personalize/latest/dg/working-with-predefined-recipes.html" rel="noopener noreferrer"&gt;Amazon Personalize&lt;/a&gt; even exposes a Popular Items recipe alongside personalized recommendation and ranking recipes. &lt;/p&gt;

&lt;p&gt;Popularity is particularly valuable for &lt;strong&gt;cold start&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you know almost nothing about a new user, "what is currently popular among similar visitors?" can be a much better fallback than random ordering.&lt;/p&gt;

&lt;p&gt;Trending ranking adds a time component.&lt;/p&gt;

&lt;p&gt;Instead of lifetime interactions, a system might measure:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;recent engagement / expected engagement&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;or apply exponential decay so yesterday's activity matters more than last month's.&lt;/p&gt;

&lt;p&gt;The main risk is feedback loops. Items ranked highly receive more exposure, generating more interactions, which can make them rank even higher.&lt;/p&gt;

&lt;p&gt;Production systems therefore rarely use popularity alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. BM25 and Lexical Relevance
&lt;/h2&gt;

&lt;p&gt;For search surfaces, BM25 remains an important baseline.&lt;/p&gt;

&lt;p&gt;BM25 scores how well a document matches a query based largely on term frequency, document length, and how rare the matched terms are across the corpus.&lt;/p&gt;

&lt;p&gt;It is not personalized in the same way as a feed ranker, but it remains useful for candidate ranking because it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inexpensive&lt;/li&gt;
&lt;li&gt;interpretable&lt;/li&gt;
&lt;li&gt;strong for exact textual relevance&lt;/li&gt;
&lt;li&gt;mature at large scale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern systems frequently combine lexical ranking with other signals rather than replace it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.vespa.ai/en/ranking/phased-ranking.html" rel="noopener noreferrer"&gt;Vespa&lt;/a&gt;, for example, demonstrates first-phase ranking that combines &lt;code&gt;bm25(title)&lt;/code&gt; with freshness before applying a more expensive XGBoost model during a later ranking phase. &lt;/p&gt;

&lt;p&gt;That is a good example of what production ranking usually looks like: &lt;strong&gt;multiple models doing different jobs at different stages&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Content-Based Ranking
&lt;/h2&gt;

&lt;p&gt;Content-based systems compare user preferences with item attributes.&lt;/p&gt;

&lt;p&gt;For a news app, those features might include topic, author, language, embedding, or publication time.&lt;/p&gt;

&lt;p&gt;For a marketplace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;category&lt;/li&gt;
&lt;li&gt;price&lt;/li&gt;
&lt;li&gt;brand&lt;/li&gt;
&lt;li&gt;seller attributes&lt;/li&gt;
&lt;li&gt;product embedding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a dating product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interests&lt;/li&gt;
&lt;li&gt;profile features&lt;/li&gt;
&lt;li&gt;location&lt;/li&gt;
&lt;li&gt;stated preferences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Content-based ranking is especially useful when interaction data is sparse.&lt;/p&gt;

&lt;p&gt;A new item may have zero clicks, but its content still tells you something about who might want it.&lt;/p&gt;

&lt;p&gt;Modern versions often replace manually selected categories with learned embeddings, allowing semantically similar items to sit near one another in vector space.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Collaborative Filtering
&lt;/h2&gt;

&lt;p&gt;Collaborative filtering learns from patterns across users rather than relying entirely on item attributes.&lt;/p&gt;

&lt;p&gt;The intuition is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Users who behaved similarly in the past may prefer similar items in the future.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This can be powerful when a platform has substantial interaction data because the system can discover relationships that were never explicitly encoded.&lt;/p&gt;

&lt;p&gt;The weakness is equally familiar: cold start.&lt;/p&gt;

&lt;p&gt;A new user has little behavioral history. A new item has few interactions.&lt;/p&gt;

&lt;p&gt;That is why collaborative filtering is commonly combined with content signals, popularity, or other fallback strategies rather than deployed alone.&lt;/p&gt;

&lt;p&gt;For teams deciding whether candidate generation and candidate ordering should live in the same system, it helps to distinguish broader recommendation infrastructure from a dedicated ranking API.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Matrix Factorization
&lt;/h2&gt;

&lt;p&gt;Matrix factorization is one of the classic approaches for estimating user-item affinity.&lt;/p&gt;

&lt;p&gt;Imagine a giant matrix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rows are users&lt;/li&gt;
&lt;li&gt;columns are items&lt;/li&gt;
&lt;li&gt;cells contain interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most cells are empty.&lt;/p&gt;

&lt;p&gt;Matrix factorization learns smaller latent representations for users and items so the system can estimate preferences even where no direct interaction exists.&lt;/p&gt;

&lt;p&gt;Those hidden factors might indirectly represent concepts such as genre preference, price sensitivity, style, or content taste.&lt;/p&gt;

&lt;p&gt;Matrix factorization became particularly well known through recommender systems because it can capture behavioral relationships that simple popularity ranking misses.&lt;/p&gt;

&lt;p&gt;Its biggest limitation for modern real-time products is context.&lt;/p&gt;

&lt;p&gt;User A may generally prefer technology content, but what they want at 8 AM on a phone can differ from what they want Saturday evening on a TV.&lt;/p&gt;

&lt;p&gt;That pushed production systems toward models that can incorporate richer contextual features.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Gradient-Boosted Decision Trees
&lt;/h2&gt;

&lt;p&gt;Gradient-boosted trees, including XGBoost and LightGBM-style models, remain highly practical ranking tools.&lt;/p&gt;

&lt;p&gt;They perform especially well when you have structured features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;historical CTR&lt;/li&gt;
&lt;li&gt;creator quality&lt;/li&gt;
&lt;li&gt;price&lt;/li&gt;
&lt;li&gt;freshness&lt;/li&gt;
&lt;li&gt;user-item affinity&lt;/li&gt;
&lt;li&gt;query relevance&lt;/li&gt;
&lt;li&gt;inventory information&lt;/li&gt;
&lt;li&gt;session features&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Their appeal is that they can model nonlinear interactions without the serving complexity of a very large neural network.&lt;/p&gt;

&lt;p&gt;Vespa supports XGBoost and LightGBM directly inside ranking pipelines, including using a cheap first-phase scorer and a boosted model only on the strongest candidates.&lt;/p&gt;

&lt;p&gt;This cascade is important.&lt;/p&gt;

&lt;p&gt;Running your most expensive model over 100 candidates is very different from running it over 100,000.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Deep Neural Ranking
&lt;/h2&gt;

&lt;p&gt;Deep ranking models become attractive when the relationships between users, items, and context are too complex for manually engineered interactions.&lt;/p&gt;

&lt;p&gt;Google's YouTube paper described separate deep neural models for candidate generation and ranking at one of the world's largest recommendation systems. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/pinterest-engineering/multi-task-learning-and-calibration-for-utility-based-home-feed-ranking-64087a7bcbad" rel="noopener noreferrer"&gt;Pinterest has also documented neural Homefeed ranking systems&lt;/a&gt; that consume user, Pin, and contextual signals to predict user actions. Pinterest later evolved its ranking toward multi-task learning so the system could model several engagement objectives rather than optimizing a single action. &lt;/p&gt;

&lt;p&gt;Deep models can capture sophisticated behavioral relationships, but the trade-offs are real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;greater data requirements&lt;/li&gt;
&lt;li&gt;more difficult debugging&lt;/li&gt;
&lt;li&gt;higher inference costs&lt;/li&gt;
&lt;li&gt;more complex training infrastructure&lt;/li&gt;
&lt;li&gt;harder model observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A neural ranker is not automatically better simply because it is more complex.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Learning-to-Rank
&lt;/h2&gt;

&lt;p&gt;Learning-to-rank, or LTR, is specifically designed for &lt;strong&gt;ordered results&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of simply predicting "will the user click?", an LTR model learns how candidates should be ordered relative to one another.&lt;/p&gt;

&lt;p&gt;There are three broad approaches:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pointwise:&lt;/strong&gt; predict a relevance score independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pairwise:&lt;/strong&gt; learn whether item A should rank above item B.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listwise:&lt;/strong&gt; optimize the ordering of an entire list.&lt;/p&gt;

&lt;p&gt;One of the b&lt;a href="https://www.microsoft.com/en-us/research/publication/from-ranknet-to-lambdarank-to-lambdamart-an-overview/" rel="noopener noreferrer"&gt;est-known approaches is LambdaMART&lt;/a&gt;, which combines LambdaRank with boosted decision trees. Microsoft's work describes LambdaMART as a successful real-world ranking method, while modern XGBoost implements ranking objectives for NDCG, MAP, and pairwise ranking. &lt;/p&gt;

&lt;p&gt;NDCG is especially useful because it cares about &lt;strong&gt;where&lt;/strong&gt; relevant results appear, not merely whether they appear.&lt;/p&gt;

&lt;p&gt;That matches the product problem much better than ordinary classification.&lt;/p&gt;

&lt;p&gt;There is one major caveat: logged interaction data contains position bias. Results already shown near the top receive more clicks simply because users see them first. XGBoost's current LTR implementation includes an unbiased LambdaMART option specifically to address position-dependent click data. &lt;/p&gt;

&lt;h2&gt;
  
  
  Production ranking systems usually combine algorithms
&lt;/h2&gt;

&lt;p&gt;The biggest misconception is that mature teams eventually discover one perfect ranker.&lt;/p&gt;

&lt;p&gt;They usually build a cascade.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://engineering.linkedin.com/teams/data/artificial-intelligence/feed" rel="noopener noreferrer"&gt;LinkedIn's published feed architecture&lt;/a&gt; includes multiple first-pass rankers, a second-pass ranker, and a final reranking layer. &lt;/p&gt;

&lt;p&gt;Pinterest describes retrieval, pre-ranking, ranking, and reranking in its Homefeed recommendation funnel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://research.atspotify.com/2025/9/calibrated-recommendations-with-contextual-bandits-on-spotify-homepage" rel="noopener noreferrer"&gt;Spotify recently deployed contextual-bandit-based calibration&lt;/a&gt; on its Home page to balance content types dynamically. In its reported online experiment, the approach improved overall impression-to-stream efficiency by 3.93%, consumption by 1.28%, and Home activity by 1.54% versus its baseline.&lt;/p&gt;

&lt;p&gt;That last step matters because a production ranker is rarely optimizing only relevance.&lt;/p&gt;

&lt;p&gt;It may also need to balance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;diversity&lt;/li&gt;
&lt;li&gt;freshness&lt;/li&gt;
&lt;li&gt;exploration&lt;/li&gt;
&lt;li&gt;creator fairness&lt;/li&gt;
&lt;li&gt;marketplace supply&lt;/li&gt;
&lt;li&gt;revenue&lt;/li&gt;
&lt;li&gt;long-term satisfaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once monetization enters the feed, the final ordering may also need to reconcile organic relevance with sponsored inventory. Our guides to &lt;a href="https://gortex.ai/blog/sponsored-listings-api-guide" rel="noopener noreferrer"&gt;sponsored listings architecture&lt;/a&gt; and &lt;a href="https://gortex.ai/blog/auction-api-explained" rel="noopener noreferrer"&gt;real-time ad auctions&lt;/a&gt; cover that layer separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which ranking algorithm should you use?
&lt;/h2&gt;

&lt;p&gt;For a small product, start simpler than you think.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Low interaction volume:&lt;/strong&gt; rules, popularity, and content signals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Growing feed or marketplace:&lt;/strong&gt; weighted scoring plus personalized features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strong structured behavioral data:&lt;/strong&gt; gradient-boosted models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Large-scale recommendation system:&lt;/strong&gt; deep models and multi-stage ranking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enough labeled or interaction data to optimize ordering directly:&lt;/strong&gt; learning-to-rank.&lt;/p&gt;

&lt;p&gt;The architecture matters as much as the algorithm.&lt;/p&gt;

&lt;p&gt;A cheap, explainable first-stage model with a stronger reranker can outperform an architecture that attempts to run one expensive model across every possible candidate.&lt;/p&gt;

&lt;p&gt;And if ranking is not your core infrastructure advantage, the build decision itself is worth questioning. A managed &lt;a href="https://gortex.ai/ranking-api" rel="noopener noreferrer"&gt;ranking API&lt;/a&gt; can let your application retain candidate retrieval while moving scoring, ordering, decision tracing, and eventually monetized placement into a dedicated decision layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Ranking systems usually evolve in stages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rules tell the system what must happen.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weighted scores combine known signals.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collaborative and content-based approaches personalize.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boosted and neural models learn increasingly complex relationships.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning-to-rank finally optimizes the ordering itself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The important engineering decision is not whether your stack contains the most sophisticated algorithm.&lt;/p&gt;

&lt;p&gt;It is whether the ranking system can produce better decisions, inside your latency budget, with enough control and observability to run safely in production.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Best Recommendation API for Dating Apps Under 200ms p99</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Tue, 06 Oct 2026 10:37:57 +0000</pubDate>
      <link>https://dev.to/heminjoshi/best-recommendation-api-for-dating-apps-under-200ms-p99-dll</link>
      <guid>https://dev.to/heminjoshi/best-recommendation-api-for-dating-apps-under-200ms-p99-dll</guid>
      <description>&lt;p&gt;If your dating app already generates a pool of eligible profiles and needs to re-rank those profiles for each user in under 200ms p99, the best architectural fit is a ranking API that sits after candidate generation, not a recommendation engine that tries to own matching, filtering, retrieval, and ranking at once.&lt;/p&gt;

&lt;p&gt;For that specific architecture, &lt;a href="https://gortex.ai/" rel="noopener noreferrer"&gt;Gortex&lt;/a&gt; is the option I would evaluate first, particularly if you also care about decision traces, keeping retrieval in-house, and eventually introducing monetized placements without rebuilding the ranking path. Gortex positions its decision API around candidate sets containing profiles, advertises a sub-200ms p99 budget, and returns a ranked order with decision and trace IDs. &lt;/p&gt;

&lt;p&gt;For teams that want a more mature managed ML recommender today, Recombee is the strongest alternative. If your infrastructure is heavily AWS-native, Amazon Personalize Personalized-Ranking-v2 also deserves a benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which dating recommendation API should you choose?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Real-time ranking&lt;/th&gt;
&lt;th&gt;&amp;lt;200ms positioning&lt;/th&gt;
&lt;th&gt;Candidate re-ranking&lt;/th&gt;
&lt;th&gt;Main trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gortex&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dating apps that already generate eligible profiles&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Sub-200ms p99&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Private beta; learned ranker is roadmap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Recombee&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mature managed recommendations with minimal ML work&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&amp;lt;200ms stated&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong recommendation controls&lt;/td&gt;
&lt;td&gt;Broader recommendation platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon Personalize&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS-native applications&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Low-latency service, benchmark p99 yourself&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Native Personalized-Ranking-v2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;More AWS/data plumbing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Custom ML stack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Large teams where matching is core IP&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;You control it&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Highest engineering burden&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important distinction is that a dating app is not simply recommending "items."&lt;/p&gt;

&lt;p&gt;It is ranking people for people.&lt;/p&gt;

&lt;p&gt;That changes what a good system needs to optimize.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is dating-app ranking different from normal recommendations?
&lt;/h2&gt;

&lt;p&gt;Traditional ecommerce recommenders usually model a one-way preference:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;User A is likely to like Product X.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dating systems are fundamentally different because a useful recommendation depends on &lt;strong&gt;reciprocity&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;User A should be interested in User B, but User B should also plausibly be interested in User A.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Research describes dating as a reciprocal recommendation problem rather than a conventional user-item recommendation problem. An AAAI paper based on a production dating platform specifically notes that online dating requires understanding bidirectional preferences between potential partners. &lt;/p&gt;

&lt;p&gt;Earlier deployed research also found that people-to-people recommendation systems need to consider both sides of the interaction rather than optimizing only for whether the receiving user clicks a recommendation. &lt;/p&gt;

&lt;p&gt;That means the ranking objective should eventually move beyond:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;P(profile click)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;toward something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;P(A likes B)
×
P(B likes A)
×
P(meaningful interaction | match)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may also need to balance activity, freshness, exposure, safety, diversity, and opportunity across the marketplace.&lt;/p&gt;

&lt;p&gt;This is one reason to separate profile eligibility, candidate retrieval, and ranking rather than forcing everything into one model.&lt;/p&gt;

&lt;p&gt;Gortex explains that same architectural boundary in its guide to &lt;a href="https://gortex.ai/blog/ranking-api-explained-how-to-choose-one" rel="noopener noreferrer"&gt;ranking APIs and candidate re-ranking&lt;/a&gt;: retrieval determines which candidates are possible; ranking determines their order.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Gortex
&lt;/h2&gt;

&lt;p&gt;The cleanest dating architecture usually starts by handling non-negotiable constraints yourself.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2M profiles
      ↓
Age / preference eligibility
      ↓
Distance
      ↓
Blocked + reported users removed
      ↓
Already-seen / unavailable profiles removed
      ↓
500–1,500 eligible candidates
      ↓
REAL-TIME RANKER
      ↓
Top profiles for this user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is where &lt;a href="https://gortex.ai/" rel="noopener noreferrer"&gt;Gortex&lt;/a&gt; fits naturally.&lt;/p&gt;

&lt;p&gt;Rather than replacing your user database or deciding who is eligible, your application sends a recipient, context, and candidate set to the decision layer. Gortex explicitly lists profiles among the candidate types it can rank and says its personalization API operates inside a sub-200ms p99 budget. &lt;/p&gt;

&lt;p&gt;Its API boundary is effectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Eligible profiles in
       ↓
POST /v1/decide
       ↓
Personalized ordering out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is especially attractive for dating because your product should retain ownership of hard constraints.&lt;/p&gt;

&lt;p&gt;A ranking algorithm should never be allowed to override a block, safety restriction, age preference, geographic rule, or other fundamental eligibility requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Gortex is particularly interesting
&lt;/h3&gt;

&lt;p&gt;There are three architectural advantages.&lt;/p&gt;

&lt;p&gt;First, you keep retrieval. Gortex says candidate generation remains in your application, so you do not need to re-platform the data layer just to add ranking. &lt;/p&gt;

&lt;p&gt;Second, each response includes a decision ID and trace ID, giving the application a path toward explaining and debugging why a profile received a particular position.&lt;/p&gt;

&lt;p&gt;Third, Gortex uses the same decision layer for organic ranking and potential sponsored placement. That may not matter for a dating app today, but it avoids designing personalization as a dead end if the platform later introduces boosts or paid discovery surfaces.&lt;/p&gt;

&lt;p&gt;You can see the product boundary more directly on the &lt;a href="https://gortex.ai/recommendation-engine-api" rel="noopener noreferrer"&gt;Gortex Recommendation Engine API&lt;/a&gt; and &lt;a href="https://gortex.ai/personalization-api" rel="noopener noreferrer"&gt;Gortex Personalization API&lt;/a&gt; pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Recombee
&lt;/h2&gt;

&lt;p&gt;If your top priority is mature managed personalization with minimal ML engineering, Recombee is a serious contender.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.recombee.com/api" rel="noopener noreferrer"&gt;Recombee&lt;/a&gt; states that recommendations are updated immediately after user actions and returned in less than 200ms.&lt;/p&gt;

&lt;p&gt;Its API can also recommend users to users, which is particularly relevant for dating rather than traditional product recommendation. The platform supports interaction tracking, relevance controls, recommendation rotation and personalized ranking behavior. &lt;/p&gt;

&lt;p&gt;A dating app might send events such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;profile impression&lt;/li&gt;
&lt;li&gt;profile opened&lt;/li&gt;
&lt;li&gt;like&lt;/li&gt;
&lt;li&gt;pass&lt;/li&gt;
&lt;li&gt;match&lt;/li&gt;
&lt;li&gt;message sent&lt;/li&gt;
&lt;li&gt;message replied&lt;/li&gt;
&lt;li&gt;conversation continued&lt;/li&gt;
&lt;li&gt;hide&lt;/li&gt;
&lt;li&gt;block&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recombee's rotation controls are useful as well. A dating experience should not repeatedly return the same small set of highly ranked profiles simply because the model has high confidence in them. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Recombee when:&lt;/strong&gt; you want a mature recommendation-as-a-service platform and want the vendor to handle more of the personalization machinery.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Amazon Personalize
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/personalize/latest/dg/native-recipe-personalized-ranking-v2.html" rel="noopener noreferrer"&gt;Amazon Personalize&lt;/a&gt; is particularly interesting when you already generate the profile candidates yourself.&lt;/p&gt;

&lt;p&gt;Its Personalized-Ranking-v2 recipe was built specifically to accept an input collection and reorder it for an individual user. AWS says it supports up to five million items and offers lower latency than its previous Personalized-Ranking recipe. &lt;/p&gt;

&lt;p&gt;The request pattern is almost exactly what a dating app needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_123

candidate profiles:
profile_17
profile_42
profile_88
profile_103
...

         ↓

GetPersonalizedRanking

         ↓

profiles ordered by predicted interest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS also supports real-time personalization as new interaction data is recorded.&lt;/p&gt;

&lt;p&gt;However, I would not interpret "lower latency" as proof that your own workload will achieve &amp;lt;200ms p99.&lt;/p&gt;

&lt;p&gt;Benchmark it.&lt;/p&gt;

&lt;p&gt;Run requests from your production region with your actual candidate count, filters, context fields, concurrency and network path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Amazon Personalize when:&lt;/strong&gt; AWS integration matters more than having an opinionated ranking product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should happen before the ranking API?
&lt;/h2&gt;

&lt;p&gt;Do not send every dating profile into the ranker.&lt;/p&gt;

&lt;p&gt;Perform hard eligibility filtering first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Candidate generation
       ↓
Age / preference filters
       ↓
Geo constraints
       ↓
Safety / block lists
       ↓
Availability / activity
       ↓
Already seen / matched profiles
       ↓
Ranking API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let the ranker answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Among eligible profiles, who should this person see first?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That architecture also makes your latency target much more realistic.&lt;/p&gt;

&lt;p&gt;A useful deeper explanation is &lt;a href="https://gortex.ai/blog/recommendation-engine-architecture" rel="noopener noreferrer"&gt;Gortex's recommendation-engine architecture guide&lt;/a&gt;, which separates retrieval, ranking, re-ranking, serving, and logging rather than treating recommendation as one black box. &lt;/p&gt;

&lt;h2&gt;
  
  
  What should a dating app optimize for?
&lt;/h2&gt;

&lt;p&gt;Do not optimize your recommendation API solely for profile clicks or likes.&lt;/p&gt;

&lt;p&gt;The meaningful funnel is closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Impression
   ↓
Profile view
   ↓
Like
   ↓
Mutual match
   ↓
Message
   ↓
Reply
   ↓
Sustained conversation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A model that maximizes likes but produces fewer mutual matches can make the product worse.&lt;/p&gt;

&lt;p&gt;Likewise, ranking the same highly popular profiles for everyone can create an exposure problem. Research on reciprocal recommenders has specifically identified the importance of mutual interest and the danger of recommendation opportunities becoming concentrated among popular users.&lt;/p&gt;

&lt;p&gt;Your experiment should therefore measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mutual match rate&lt;/li&gt;
&lt;li&gt;replies per match&lt;/li&gt;
&lt;li&gt;meaningful conversations&lt;/li&gt;
&lt;li&gt;hide/block/report rate&lt;/li&gt;
&lt;li&gt;profile diversity&lt;/li&gt;
&lt;li&gt;exposure concentration&lt;/li&gt;
&lt;li&gt;retention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not merely CTR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which recommendation API would I choose?
&lt;/h2&gt;

&lt;p&gt;For the exact requirement:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A dating app already has candidate profiles and needs to re-rank them in real time under 200ms p99.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My evaluation order would be:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Gortex&lt;/strong&gt; - best architectural fit if you want candidate-in/ranked-profiles-out, sub-200ms p99 positioning, traceable decisions, and a ranking layer you can reuse across future surfaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Recombee&lt;/strong&gt; - strongest mature managed recommender if you want proven real-time personalization with minimal ML ownership.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Amazon Personalize&lt;/strong&gt; - strongest AWS-native re-ranking option, particularly when your candidate-generation stack already lives inside AWS.&lt;/p&gt;

&lt;p&gt;The final decision should come from a shadow test and then an A/B test.&lt;/p&gt;

&lt;p&gt;Run the same candidate sets through each system and measure:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;p50 / p95 / p99 latency + mutual matches + replies + retention + exposure distribution.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The winning API is not simply the one that predicts who a user will like.&lt;/p&gt;

&lt;p&gt;For dating, the winning system is the one that ranks profiles quickly enough for the product experience while improving the probability that both people actually want the interaction to happen.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>What Is Decisioning Infrastructure for Consumer Platforms?</title>
      <dc:creator>Hemin Joshi</dc:creator>
      <pubDate>Wed, 30 Sep 2026 03:11:58 +0000</pubDate>
      <link>https://dev.to/heminjoshi/what-is-decisioning-infrastructure-for-consumer-platforms-4715</link>
      <guid>https://dev.to/heminjoshi/what-is-decisioning-infrastructure-for-consumer-platforms-4715</guid>
      <description>&lt;p&gt;Consumer platforms make thousands or millions of decisions every second about what users see.&lt;/p&gt;

&lt;p&gt;A social platform decides which posts appear in a feed. A marketplace decides which listings appear first. A creator platform decides which creators or content to recommend. A dating app decides which profiles to surface. A job board decides which jobs should appear at the top of a candidate's search.&lt;/p&gt;

&lt;p&gt;Behind all of these experiences is a common technical problem: &lt;strong&gt;given a set of possible items, which items should be shown, in what order, and under what business rules?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditionally, companies build this capability themselves using a combination of retrieval systems, ranking models, recommendation engines, business rules, and separate advertising infrastructure. As platforms grow, this layer becomes increasingly complex to operate.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;decisioning infrastructure&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;Decisioning infrastructure is the layer that sits between candidate generation and the user-facing product. It takes candidate items and contextual information, applies ranking and business logic, determines the final ordering and monetized placements, and records the decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Decisioning Infrastructure?
&lt;/h2&gt;

&lt;p&gt;Decisioning infrastructure is a software layer responsible for making real-time decisions about what a consumer platform should display.&lt;/p&gt;

&lt;p&gt;A simplified architecture looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User + Context → Candidate Generation → Decisioning → User Interface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The candidate-generation layer answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What could we show?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The decisioning layer answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What should we show, in what order, and where should monetized inventory appear?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The distinction is important.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/machine-learning/recommendation/overview/types" rel="noopener noreferrer"&gt;Modern recommendation systems&lt;/a&gt; commonly separate &lt;strong&gt;candidate generation, scoring, and re-ranking&lt;/strong&gt;. Google describes candidate generation as narrowing a potentially huge corpus into a smaller set, followed by scoring and re-ranking to determine what ultimately appears to the user.&lt;/p&gt;

&lt;p&gt;Decisioning infrastructure extends this final part of the architecture into an explicit production layer.&lt;/p&gt;

&lt;p&gt;It can incorporate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relevance&lt;/li&gt;
&lt;li&gt;Personalization&lt;/li&gt;
&lt;li&gt;User context&lt;/li&gt;
&lt;li&gt;Freshness&lt;/li&gt;
&lt;li&gt;Business rules&lt;/li&gt;
&lt;li&gt;Inventory constraints&lt;/li&gt;
&lt;li&gt;Sponsored placements&lt;/li&gt;
&lt;li&gt;Monetization objectives&lt;/li&gt;
&lt;li&gt;Diversity requirements&lt;/li&gt;
&lt;li&gt;Eligibility rules&lt;/li&gt;
&lt;li&gt;Experimentation&lt;/li&gt;
&lt;li&gt;Decision logging and explanations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of embedding all of this logic directly into an application, a platform can expose it through a dedicated decisioning service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Consumer Platforms Need a Separate Decisioning Layer
&lt;/h2&gt;

&lt;p&gt;At first, ranking can look relatively simple.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://gortex.ai/marketplaces" rel="noopener noreferrer"&gt;marketplace&lt;/a&gt; might sort products by relevance. A social network might sort posts by predicted engagement. A job board might sort jobs by relevance to a candidate.&lt;/p&gt;

&lt;p&gt;As the product grows, however, ranking becomes a multi-objective problem.&lt;/p&gt;

&lt;p&gt;The platform may simultaneously need to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the user is likely to find relevant&lt;/li&gt;
&lt;li&gt;What is available right now&lt;/li&gt;
&lt;li&gt;What content is fresh&lt;/li&gt;
&lt;li&gt;What the user has already seen&lt;/li&gt;
&lt;li&gt;Whether an item is eligible for the surface&lt;/li&gt;
&lt;li&gt;Whether a business rule should override the model&lt;/li&gt;
&lt;li&gt;Whether sponsored inventory should be displayed&lt;/li&gt;
&lt;li&gt;How much sponsored inventory the experience can tolerate&lt;/li&gt;
&lt;li&gt;How monetization affects the final ordering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates an infrastructure problem rather than simply a machine-learning problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/blog/engineering/recommendations/building-a-large-scale-recommendation-system-people-you-may-know" rel="noopener noreferrer"&gt;LinkedIn, for example, describes a multi-stage ranking architecture&lt;/a&gt; in which candidate generation first selects candidates from a very large inventory, followed by ranking stages that calibrate and reduce the candidate set against a common objective.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://engineering.fb.com/2018/10/02/ml-applications/under-the-hood-facebook-marketplace-powered-by-artificial-intelligence/" rel="noopener noreferrer"&gt;Facebook Marketplace&lt;/a&gt; similarly uses retrieval and ranking as separate stages because the system needs to narrow a massive product inventory before applying more computationally expensive ranking models. &lt;/p&gt;

&lt;p&gt;The difficult part is therefore not just creating a model.&lt;/p&gt;

&lt;p&gt;It is making the &lt;strong&gt;decision reliably, quickly, consistently, and observably in production&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decisioning Infrastructure vs Retrieval
&lt;/h2&gt;

&lt;p&gt;One of the most important distinctions is between retrieval and decisioning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieval asks: "What are the candidates?"
&lt;/h3&gt;

&lt;p&gt;Suppose a marketplace has 10 million listings.&lt;/p&gt;

&lt;p&gt;It would be impractical to run a sophisticated ranking model against every listing for every request.&lt;/p&gt;

&lt;p&gt;Instead, retrieval systems narrow the inventory to a manageable candidate set.&lt;/p&gt;

&lt;p&gt;Modern retrieval systems can use techniques such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vector embeddings&lt;/li&gt;
&lt;li&gt;Approximate nearest-neighbor search&lt;/li&gt;
&lt;li&gt;Collaborative filtering&lt;/li&gt;
&lt;li&gt;Content similarity&lt;/li&gt;
&lt;li&gt;User history&lt;/li&gt;
&lt;li&gt;Geographic signals&lt;/li&gt;
&lt;li&gt;Popularity&lt;/li&gt;
&lt;li&gt;Graph relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/machine-learning/recommendation/overview/candidate-generation" rel="noopener noreferrer"&gt;Google's recommendation architecture&lt;/a&gt; describes candidate generation as the first stage, where a huge corpus is reduced to a smaller group of potentially relevant candidates. &lt;/p&gt;

&lt;p&gt;Two-tower architectures are one example of how this can be implemented at scale. &lt;a href="https://docs.cloud.google.com/architecture/implement-two-tower-retrieval-large-scale-candidate-generation" rel="noopener noreferrer"&gt;Google Cloud describes using separate query and candidate representations&lt;/a&gt; so that candidate embeddings can be precomputed and retrieved efficiently at serving time. &lt;/p&gt;

&lt;h3&gt;
  
  
  Decisioning asks: "What should actually be shown?"
&lt;/h3&gt;

&lt;p&gt;Once the platform has, for example, 200 candidates, it can apply more sophisticated logic.&lt;/p&gt;

&lt;p&gt;The system might determine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Candidate A → organic position 1
Candidate B → organic position 2
Sponsored Candidate C → sponsored slot 3
Candidate D → organic position 4
Candidate E → organic position 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This final decision can involve many signals and constraints that don't belong in the retrieval layer.&lt;/p&gt;

&lt;p&gt;That distinction becomes especially important when monetization is involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ranking and Monetization Are Closely Connected
&lt;/h2&gt;

&lt;p&gt;Consumer platforms increasingly need to monetize the same surfaces that users depend on for discovery.&lt;/p&gt;

&lt;p&gt;A marketplace might sell sponsored product placements.&lt;/p&gt;

&lt;p&gt;A creator platform might offer promoted creator listings.&lt;/p&gt;

&lt;p&gt;A job board might sell sponsored job placements.&lt;/p&gt;

&lt;p&gt;A discovery platform might offer promoted products.&lt;/p&gt;

&lt;p&gt;This creates a fundamental tension.&lt;/p&gt;

&lt;p&gt;If sponsored content is handled by a completely separate advertising system, the application may effectively have two decision-makers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ranking engine&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which organic items should appear?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Ad system&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which sponsored items should appear?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application then has to merge the outputs.&lt;/p&gt;

&lt;p&gt;That architecture can become difficult to maintain because relevance, monetization, eligibility, and placement logic can evolve independently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arxiv.org/abs/2607.14418" rel="noopener noreferrer"&gt;Research on sponsored-search systems&lt;/a&gt; also highlights why this is a genuine optimization problem. A 2026 field experiment on sponsored-search ad load found that increasing sponsored slots can increase revenue while also reducing conversions and engagement, with the trade-off varying by query and advertiser composition. &lt;/p&gt;

&lt;p&gt;The implication is straightforward: &lt;strong&gt;monetization cannot always be treated as an independent layer bolted onto ranking.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The platform needs a decision about the entire surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does a Decisioning API Look Like?
&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://gortex.ai/decision-engine" rel="noopener noreferrer"&gt;decisioning infrastructure&lt;/a&gt; provider can expose this capability through an API.&lt;/p&gt;

&lt;p&gt;For example, Gortex describes itself as a decisioning infrastructure layer for consumer platforms. Its API accepts a recipient, context, and candidate set through a single &lt;code&gt;POST /v1/decide&lt;/code&gt; endpoint and returns ranked items together with sponsored placements and decision identifiers. &lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /v1/decide

{
  "recipient": {
    "id": "user_8120"
  },
  "context": {
    "surface": "home_feed"
  },
  "items": [
    ...
  ]
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response can contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ranked"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sponsored"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decision_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important architectural idea is that the platform does not need to replace its existing retrieval infrastructure.&lt;/p&gt;

&lt;p&gt;It can continue generating candidates using its own systems and then send those candidates to a decisioning layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does Decisioning Infrastructure Actually Replace?
&lt;/h2&gt;

&lt;p&gt;It does not necessarily replace every component of a recommendation stack.&lt;/p&gt;

&lt;p&gt;A useful way to think about the architecture is:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Main responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data / events&lt;/td&gt;
&lt;td&gt;Collect behavioral and product signals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Candidate generation&lt;/td&gt;
&lt;td&gt;Find items that could be relevant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decisioning&lt;/td&gt;
&lt;td&gt;Determine what should actually be shown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monetization&lt;/td&gt;
&lt;td&gt;Determine eligible sponsored placements and commercial constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;Render the final experience&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The exact boundaries vary by company.&lt;/p&gt;

&lt;p&gt;Some platforms may already have excellent retrieval but lack a reusable ranking layer. Others may have ranking models but struggle to integrate sponsored inventory. Some may have separate systems for each surface.&lt;/p&gt;

&lt;p&gt;The value of decisioning infrastructure is therefore less about introducing "another recommender" and more about &lt;strong&gt;standardizing the final decision layer&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Latency Matters
&lt;/h2&gt;

&lt;p&gt;Decisioning happens directly on the user request path.&lt;/p&gt;

&lt;p&gt;If a consumer opens a feed and the decisioning service takes too long to respond, the latency becomes part of the product experience.&lt;/p&gt;

&lt;p&gt;This is why &lt;a href="https://docs.cloud.google.com/architecture/implement-two-tower-retrieval-large-scale-candidate-generation" rel="noopener noreferrer"&gt;production recommendation systems&lt;/a&gt; typically use multi-stage architectures. Retrieval reduces the candidate space first, allowing more sophisticated ranking to operate on a much smaller set. Google Cloud's reference architecture specifically describes reducing millions of candidates to hundreds before ranking them. &lt;/p&gt;

&lt;p&gt;A decisioning service therefore needs to operate within a predictable latency budget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gortex.ai/" rel="noopener noreferrer"&gt;Gortex&lt;/a&gt; currently describes a target of &lt;strong&gt;under 200 ms p99 latency&lt;/strong&gt; and provides an API-based architecture designed to sit between candidate generation and the consumer-facing surface. Its website also lists seven SDKs and OpenAPI 3.1 as part of the integration architecture. &lt;/p&gt;

&lt;p&gt;For an engineering team, these characteristics matter because the decision layer needs to behave more like infrastructure than a dashboard or analytics tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explainability Becomes Part of the Infrastructure
&lt;/h2&gt;

&lt;p&gt;Ranking decisions can become difficult to debug.&lt;/p&gt;

&lt;p&gt;Suppose an item unexpectedly moves from position two to position twenty.&lt;/p&gt;

&lt;p&gt;An engineer may need to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which signals affected the ranking?&lt;/li&gt;
&lt;li&gt;Which rules were applied?&lt;/li&gt;
&lt;li&gt;Was the item eligible?&lt;/li&gt;
&lt;li&gt;Did a sponsored placement change the ordering?&lt;/li&gt;
&lt;li&gt;Which version of the decision logic produced the response?&lt;/li&gt;
&lt;li&gt;What happened during that particular request?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without decision-level logging, debugging can become difficult.&lt;/p&gt;

&lt;p&gt;Gortex includes a decision ID and trace ID in its API response and describes its architecture as providing a decision trace for understanding why items were placed where they were. &lt;/p&gt;

&lt;p&gt;This is particularly useful when ranking becomes part of the platform's core infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decisioning Infrastructure Is Not the Same as a Recommendation Engine
&lt;/h2&gt;

&lt;p&gt;The terms are related, but they are not identical.&lt;/p&gt;

&lt;p&gt;A recommendation engine primarily focuses on predicting which items a user may want.&lt;/p&gt;

&lt;p&gt;Decisioning infrastructure is broader.&lt;/p&gt;

&lt;p&gt;It can consume recommendations or retrieved candidates and then combine them with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;Rules&lt;/li&gt;
&lt;li&gt;Ranking&lt;/li&gt;
&lt;li&gt;Eligibility&lt;/li&gt;
&lt;li&gt;Monetization&lt;/li&gt;
&lt;li&gt;Placement constraints&lt;/li&gt;
&lt;li&gt;Business objectives&lt;/li&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/machine-learning/recommendation/dnn/scoring" rel="noopener noreferrer"&gt;Google's recommendation documentation&lt;/a&gt; itself emphasizes that scoring objectives matter because optimizing a single metric such as clicks can produce undesirable outcomes. &lt;/p&gt;

&lt;p&gt;A decisioning layer gives engineering teams a place to explicitly manage these competing objectives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Can Decisioning Infrastructure Be Used?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://gortex.ai/solutions" rel="noopener noreferrer"&gt;concept applies anywhere a platform&lt;/a&gt; has a set of candidates competing for limited user-facing slots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Social feeds
&lt;/h3&gt;

&lt;p&gt;Rank posts, creators, communities, or other content while applying freshness, personalization, and placement rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Marketplaces
&lt;/h3&gt;

&lt;p&gt;Rank products or listings while considering relevance, seller quality, inventory, and monetized placements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creator platforms
&lt;/h3&gt;

&lt;p&gt;Rank creators, profiles, or content and optionally introduce sponsored discovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dating platforms
&lt;/h3&gt;

&lt;p&gt;Rank potential profiles using user and contextual signals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Job boards
&lt;/h3&gt;

&lt;p&gt;Rank jobs based on candidate relevance while supporting promoted or sponsored jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Content platforms
&lt;/h3&gt;

&lt;p&gt;Rank articles, videos, podcasts, or user-generated content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discovery products
&lt;/h3&gt;

&lt;p&gt;Rank products, services, locations, companies, or other entities where multiple candidates compete for visibility.&lt;/p&gt;

&lt;p&gt;Gortex explicitly positions its decisioning API for feeds, recommendations, marketplaces, content, personalization, and sponsored listings. &lt;/p&gt;

&lt;h2&gt;
  
  
  What Should Companies Look for in Decisioning Infrastructure?
&lt;/h2&gt;

&lt;p&gt;For teams evaluating this category, several capabilities are particularly important.&lt;/p&gt;

&lt;h3&gt;
  
  
  Low-latency serving
&lt;/h3&gt;

&lt;p&gt;The decision layer sits close to the user request, so predictable latency is critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexible candidate inputs
&lt;/h3&gt;

&lt;p&gt;Teams should be able to use their existing retrieval systems rather than rebuild their entire recommendation stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ranking flexibility
&lt;/h3&gt;

&lt;p&gt;Different surfaces need different objectives. A marketplace, feed, and job board should not necessarily use the same ranking strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monetization support
&lt;/h3&gt;

&lt;p&gt;If sponsored inventory is part of the product roadmap, the infrastructure should support it without forcing the application to maintain a completely separate decision path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability
&lt;/h3&gt;

&lt;p&gt;Decision IDs, traces, logs, and reproducibility make ranking systems significantly easier to debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  API-first integration
&lt;/h3&gt;

&lt;p&gt;A decisioning layer should fit into existing engineering infrastructure rather than require a complete platform migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Versioning and experimentation
&lt;/h3&gt;

&lt;p&gt;Ranking logic changes frequently. Teams need to understand which version produced a particular decision and safely test changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gortex as a Decisioning Infrastructure Layer
&lt;/h2&gt;

&lt;p&gt;For consumer platforms that already have candidate-generation infrastructure but do not want to build and maintain another ranking and monetization layer internally, Gortex represents one approach to this architecture.&lt;/p&gt;

&lt;p&gt;Gortex describes is &lt;strong&gt;the layer between candidate generation and what users see&lt;/strong&gt;. Its single decision endpoint is designed to rank candidates and fill sponsored slots within the same response. &lt;/p&gt;

&lt;p&gt;The distinction is important.&lt;/p&gt;

&lt;p&gt;A company does not necessarily need to throw away its existing search, vector database, recommendation engine, or candidate-generation pipeline.&lt;/p&gt;

&lt;p&gt;Instead, the architecture can look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User Request
     ↓
Existing Retrieval / Candidate Generation
     ↓
       Gortex
     ↓
Ranking + Decisioning
     ↓
Sponsored Slot Decision
     ↓
Decision Trace
     ↓
Consumer Surface
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes Gortex particularly relevant for engineering teams building products where &lt;strong&gt;ranking is becoming infrastructure rather than an isolated feature&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.g2.com/sellers/gortex" rel="noopener noreferrer"&gt;G2 similarly describes Gortex&lt;/a&gt; as a ranking and monetization API for consumer platforms, including social feeds, marketplaces, creator platforms, dating apps, and job boards. &lt;/p&gt;

&lt;p&gt;Gortex is listed as being in private beta, so its capabilities and production availability should be evaluated directly with founder before adopting it for a production workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future of Consumer Platform Decisioning
&lt;/h2&gt;

&lt;p&gt;The underlying trend is bigger than recommendation systems alone.&lt;/p&gt;

&lt;p&gt;Consumer platforms are moving from simple "sort this list" experiences toward complex decision systems where relevance, personalization, business objectives, monetization, and policy all influence what users see.&lt;/p&gt;

&lt;p&gt;The architecture increasingly resembles:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieve → Rank → Apply Constraints → Monetize → Explain → Learn&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is why decisioning deserves to be treated as its own infrastructure layer.&lt;/p&gt;

&lt;p&gt;The retrieval system determines the possibilities.&lt;/p&gt;

&lt;p&gt;The decisioning layer determines the outcome.&lt;/p&gt;

&lt;p&gt;For small products, that logic may live inside a few application functions. For a growing consumer platform, it can become a critical piece of infrastructure that deserves dedicated APIs, latency guarantees, observability, versioning, and clear ownership.&lt;/p&gt;

&lt;p&gt;That is the problem space decisioning infrastructure is designed to address.&lt;/p&gt;

&lt;p&gt;Gortex fits into this emerging layer by providing an API for ranking candidates, handling sponsored placements, and returning decision-level information without requiring consumer platforms to build the entire ranking-and-monetization layer from scratch.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
  </channel>
</rss>
