
Predictive Personalization
- 58 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Use machine-learning models to predict customer preferences and deliver personalized recommendations, content, and offers from behavioral signals.
About
Uses ML models on behavioral signals to predict customer preferences and personalize recommendations, content, and offers. A developer uses it for model-driven personalization beyond rule-based approaches.
- ML models predicting customer preferences from behavioral signals
- Personalized recommendations, content, and offers
Predictive Personalization by the numbers
- 58 all-time installs (skills.sh)
- Ranked #903 of 2,064 Data Science & ML skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill predictive-personalizationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 58 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Use machine-learning models to predict customer preferences and deliver personalized recommendations, content, and offers from behavioral signals.
Files
Predictive Personalization
Overview
Predictive personalization tailors the shopping experience to each visitor — showing relevant product recommendations, personalized content, and targeted offers based on behavior, purchase history, and patterns from similar customers. For most merchants, dedicated personalization apps deliver this without any custom ML code. Building a custom recommendation engine only makes sense for headless stores with significant traffic (100k+ monthly visitors) where app costs or data control requirements justify the complexity.
When to Use This Skill
- When your store shows the same products to every visitor regardless of their behavior
- When you want to add "Recommended for You" sections to your homepage, PDP, or cart
- When email campaigns send the same products to your entire list
- When conversion rates are plateauing and you need a lift from relevance
- When ready to move beyond rule-based merchandising to data-driven personalization
Core Instructions
Step 1: Choose the right personalization tool
| Platform | Best For | Shopify | WooCommerce | BigCommerce | Price |
|---|---|---|---|---|---|
| Rebuy | Product recommendations, cross-sell/upsell widgets | App Store | Limited | Limited | $99+/mo |
| LimeSpot | Personalization + merchandising | App Store | Plugin | App Marketplace | $18+/mo |
| Nosto | Mid-market, full homepage + email personalization | App Store | Plugin | App Marketplace | Revenue-share |
| Dynamic Yield | Enterprise, full A/B testing + personalization | Via JS tag | Via JS tag | Via JS tag | $1,000+/mo |
| Klaviyo (email) | Personalized product blocks in email flows | App Store | Plugin | App Marketplace | Included in Klaviyo |
| Custom | Headless stores, 100k+ visitors/mo | API | API | API | Dev cost |
Recommendation by store size:
- Under $1M revenue: Rebuy or LimeSpot for recommendation widgets; Klaviyo for personalized email
- $1M–$10M revenue: Nosto for full-site + email personalization
- $10M+: Dynamic Yield for enterprise personalization + experimentation
Step 2: Set up product recommendations
---
Shopify
With Rebuy: 1. Install Rebuy from the Shopify App Store 2. Go to Rebuy → Smart Cart to add AI-powered cross-sell recommendations to your cart page — no code required 3. Go to Rebuy → Data Sources to configure recommendation logic:
- "Frequently Bought Together" — products purchased together in the same order
- "Similar Products" — products with similar tags and attributes
- "Recommended for You" — personalized based on browsing history
4. Go to Rebuy → Widgets to add recommendation carousels to product pages, the cart, and the homepage 5. Rebuy connects directly to Shopify's order data to compute co-purchase patterns — no additional setup needed
With LimeSpot: 1. Install LimeSpot Personalizer from the Shopify App Store 2. Go to LimeSpot → Placements to add recommendation boxes to any page (homepage, collection, product, cart) 3. Set the recommendation strategy per placement: "Trending," "Recently Viewed," "You May Also Like," or "Frequently Bought Together" 4. LimeSpot learns from your store's behavioral data automatically
---
WooCommerce
1. Go to WooCommerce → Products → [Product] → Linked Products to add manual cross-sells and upsells per product 2. For automated ML-based recommendations: install LimeSpot for WooCommerce or Barilliance plugin 3. For email personalization: configure Klaviyo dynamic product blocks in post-purchase flows (Klaviyo's Catalog block uses purchase history to generate personalized recommendations automatically)
Alternative (simpler): install YITH WooCommerce Frequently Bought Together — it adds "Customers who bought this also bought" sections using your order history, without requiring a monthly subscription.
---
BigCommerce
1. Go to BigCommerce App Marketplace and install LimeSpot or Nosto 2. Both apps integrate with BigCommerce's product and order APIs to compute recommendations 3. For email: install Klaviyo from the BigCommerce App Marketplace and use Catalog blocks for personalized product recommendations in flows
---
Custom / Headless
For headless stores, build a recommendation engine using behavioral event data and collaborative filtering:
// Collect behavioral events for each visitor
interface PersonalizationEvent {
userId: string | null; // null for anonymous visitors
sessionId: string;
eventType: 'view' | 'add_to_cart' | 'purchase';
productId: string;
categoryId?: string;
timestamp: Date;
}
// Maintain a real-time user profile in Redis
async function updateUserProfile(event: PersonalizationEvent) {
const key = event.userId ?? `anon:${event.sessionId}`;
const recentViews = JSON.parse(await redis.get(`profile:${key}:views`) ?? '[]');
if (event.eventType === 'view') {
recentViews.unshift(event.productId);
if (recentViews.length > 50) recentViews.pop();
await redis.setex(`profile:${key}:views`, 30 * 86400, JSON.stringify(recentViews));
}
const categoryScores = JSON.parse(await redis.get(`profile:${key}:categories`) ?? '{}');
if (event.categoryId) {
const weight = { view: 1, add_to_cart: 3, purchase: 5 }[event.eventType] ?? 1;
categoryScores[event.categoryId] = (categoryScores[event.categoryId] ?? 0) + weight;
await redis.setex(`profile:${key}:categories`, 30 * 86400, JSON.stringify(categoryScores));
}
}
// Nightly batch job: build co-purchase similarity from 90-day order history
// Serve recommendations via Redis cache for sub-10ms response times
// Fallback: trending/popular items when user has no history (cold start)For most headless stores, use Nosto's or Dynamic Yield's JavaScript widget + REST API instead of building from scratch. The API surfaces the same personalization data without maintaining the recommendation engine infrastructure.
Step 3: Personalize email with dynamic product blocks
This works for all platforms via Klaviyo:
1. In any Klaviyo flow (post-purchase, win-back, browse abandonment), add a Product Block 2. Set the product source to "Personalized Recommendations" — Klaviyo uses the recipient's purchase history to select products 3. Or use "Cross-sell" — Klaviyo shows products frequently bought alongside what the customer last purchased 4. Preview the email for different customer profiles to verify recommendations vary by recipient
Step 4: Set up "Recommended for You" on the homepage
---
Shopify with Rebuy or LimeSpot
1. In the app dashboard, go to Placements → Homepage 2. Set the recommendation strategy to "Recommended for You" (requires at least one prior visit/purchase to personalize; shows trending for new visitors) 3. Use the app's theme editor widget — drag it into your homepage section in Shopify → Online Store → Themes → Customize
---
Step 5: Measure personalization impact
Always A/B test personalization before full rollout. Both Rebuy and Nosto have built-in A/B testing:
| Metric | Target | Where to Find |
|---|---|---|
| Recommendation widget CTR | > 5% | App analytics dashboard |
| Revenue attributed to recommendations | 10–20% of total | App analytics |
| AOV lift (personalized vs. control) | > 5% | App A/B test results |
| Email personalized block CTR vs. static | > 2× higher | Klaviyo flow analytics |
Best Practices
- Start with post-purchase cross-sell — "Customers who bought X also bought Y" is the highest-converting recommendation placement; set it up on the order confirmation page and in post-purchase emails
- Show "Recently Viewed" on the homepage — returning visitors who see their previously viewed products have 3–4× higher conversion rates; Rebuy and LimeSpot both support this out of the box
- Use trending/popular as the fallback — new visitors with no history should see trending products, not empty recommendation slots
- Diversify recommendations across categories — enforce a maximum of 4 items per category to avoid showing 12 near-identical products
- Test personalization vs. editorial curation — for some product types (luxury goods, gifts), curated staff picks can outperform algorithmic recommendations
Common Pitfalls
| Problem | Solution |
|---|---|
| Recommendations show already-purchased items | Configure the app to exclude previously purchased products from recommendations |
| New store with no data — recommendations look wrong | Use "Trending" or editorial curation for the first 60–90 days while behavioral data accumulates |
| Recommendations are all from one category | Enable diversity controls in app settings; most apps support "max items per category" |
| Personalized email recommendations are same for everyone | Verify Klaviyo is receiving Placed Order events from your platform; check Klaviyo → Integrations status |
Related Skills
- @cross-sell-upsell-engine
- @email-marketing-automation
- @ab-testing-ecommerce
- @customer-analytics
- @search-autocomplete
{
"context": "Tests whether the agent correctly implements behavioral event tracking with the right event types, anonymous user handling, user profile structure, category affinity weighting, recent-view sliding window, and Redis TTL as specified by the personalization skill.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Event type union",
"max_score": 8,
"description": "The event data structure defines eventType as a union of exactly these values: 'view', 'add_to_cart', 'purchase', 'search', 'wishlist', 'remove_from_cart' (all six present)"
},
{
"name": "Nullable userId field",
"max_score": 8,
"description": "The event data structure has a userId field typed as string | null (not string alone, not optional/undefined)"
},
{
"name": "Anonymous key uses sessionId",
"max_score": 9,
"description": "When userId is null, the Redis profile key falls back to a session-based key (e.g. 'anon:{sessionId}') rather than being skipped or using an empty string"
},
{
"name": "Sliding window size 50",
"max_score": 9,
"description": "Recent views are capped at 50 entries (array truncated when it exceeds 50, not some other number like 100 or 20)"
},
{
"name": "Category affinity weight for view",
"max_score": 7,
"description": "The 'view' event type contributes a weight of 1 to the category affinity score"
},
{
"name": "Category affinity weight for add_to_cart",
"max_score": 9,
"description": "The 'add_to_cart' event type contributes a weight of 3 to the category affinity score"
},
{
"name": "Category affinity weight for purchase",
"max_score": 9,
"description": "The 'purchase' event type contributes a weight of 5 to the category affinity score"
},
{
"name": "Category affinity weight for wishlist",
"max_score": 7,
"description": "The 'wishlist' event type contributes a weight of 2 to the category affinity score"
},
{
"name": "Redis profile TTL 30 days",
"max_score": 10,
"description": "User profiles are set with a TTL/expiry of exactly 30 days (2592000 seconds, i.e. 30 * 24 * 60 * 60) in Redis"
},
{
"name": "Profile stored in Redis",
"max_score": 8,
"description": "User profile data (recentViews and categoryScores) is persisted using Redis hash operations (hgetall/hmset or equivalent), not in-memory only"
},
{
"name": "Design notes: anonymous handling documented",
"max_score": 8,
"description": "design-notes.md explains how anonymous users are identified (session-based key) vs logged-in users (userId-based key)"
},
{
"name": "Design notes: TTL documented",
"max_score": 8,
"description": "design-notes.md states the data retention policy and mentions the 30-day expiry"
}
]
}
Shopper Behavior Tracking Module
Problem/Feature Description
Finley's, a mid-size online home goods retailer, wants to move toward data-driven personalization. The engineering team has been asked to build the foundational event tracking layer that will power a future recommendation engine. Right now the store has no behavioral data collection at all — every visit is anonymous and no signals are captured. Before any ML model can be trained or any recommendation served, the team needs a robust event pipeline that can record what shoppers do and build per-user profiles from those interactions.
The product manager has specified that the system must handle both logged-in customers and anonymous browsers, since many shoppers browse for weeks before creating an account. The profiles need to capture two key signals: what products a shopper has recently looked at, and which product categories they gravitate toward. These profiles will be consumed by other services, so they must be stored in Redis and expire naturally to avoid storing stale data forever.
Output Specification
Produce a TypeScript module at src/events/track.ts that:
- Defines the event data structure for behavioral tracking
- Implements a function to record events to an event store and update the user profile
- Implements profile update logic that maintains recent product views and per-category affinity scores
Also produce a brief design-notes.md file documenting:
- How the module handles anonymous vs logged-in users
- What the profile data structure looks like in Redis
- The data retention policy (TTL)
- How category affinity weights are assigned for different event types
The TypeScript code should be complete and well-typed, using Redis as the profile store. You may stub out the eventStore and redis dependencies with type-compatible interfaces rather than implementing them.
{
"context": "Tests whether the agent uses item-item collaborative filtering with the correct time window, Jaccard similarity normalization, appropriate limits on stored items, daily cache refresh, and a nightly batch rebuild pattern as specified by the personalization skill.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Item-item collaborative filtering",
"max_score": 10,
"description": "The implementation builds product-to-product similarity by finding co-occurring products in the same session (item-item approach), not user-item matrix factorization"
},
{
"name": "90-day event window",
"max_score": 10,
"description": "The query for building the co-occurrence matrix filters events to those within the last 90 days (not 30, 60, 180, or all-time)"
},
{
"name": "Session co-occurrence basis",
"max_score": 8,
"description": "Co-occurrence is grouped by session (not by user) and requires at least 2 distinct products per session"
},
{
"name": "Jaccard similarity formula",
"max_score": 12,
"description": "Similarity is computed as coCount / (countA + countB - coCount) — the Jaccard formula — not cosine, Pearson, or a raw count"
},
{
"name": "Top 50 similar items stored",
"max_score": 9,
"description": "For each product, only the top 50 most similar products are stored (not top 10, 20, 100, or all)"
},
{
"name": "24-hour Redis cache expiry",
"max_score": 10,
"description": "Similarity data in Redis is set with an expiry of 24 hours (86400 seconds), refreshed daily"
},
{
"name": "Nightly batch rebuild",
"max_score": 9,
"description": "The nightly-rebuild.ts job file shows the co-occurrence build triggered on a scheduled/nightly basis (not on every request or in real-time)"
},
{
"name": "Design notes: similarity metric",
"max_score": 8,
"description": "design-notes.md identifies the similarity metric used (Jaccard) and explains the choice"
},
{
"name": "Design notes: history window",
"max_score": 8,
"description": "design-notes.md states that purchase history from the last 90 days is used"
},
{
"name": "Design notes: cache TTL",
"max_score": 8,
"description": "design-notes.md mentions that similarity results are cached for 24 hours before being refreshed"
},
{
"name": "Purchase and cart events used",
"max_score": 8,
"description": "The co-occurrence query uses both 'purchase' and 'add_to_cart' event types (not views alone, not purchases alone)"
}
]
}
Product Similarity Engine
Problem/Feature Description
Bloom & Thread, a specialty apparel e-commerce brand, has been running for three years and has accumulated a substantial purchase history database. Their current "You May Also Like" section is hand-curated by a merchandising team and only covers the top 200 products. The engineering team has been tasked with automating this using machine learning on their existing transaction data, so every product in the catalog gets a list of related items based on real shopper behavior.
The data science team has agreed on an approach: mine the purchase and cart-add history to find which products are frequently bought or carted together in the same shopping session. Products that are co-purchased frequently are likely complementary or related. The resulting similarity scores should be precomputed and cached so that the storefront can serve "also bought" suggestions in milliseconds, and the model should refresh automatically so that seasonal patterns and new products are picked up without manual intervention.
Output Specification
Produce a TypeScript module at src/models/collaborative-filter.ts that:
- Queries session-based co-occurrence from purchase/cart history
- Computes similarity scores between products
- Stores the results in Redis for low-latency serving
Also produce a src/jobs/nightly-rebuild.ts file that shows how the model rebuild is triggered on a schedule.
Finally, write a design-notes.md documenting:
- Which similarity metric is used and why
- How many similar products are stored per item
- How long results are cached before refresh
- How far back in time purchase history is used
- How the nightly rebuild job fits into the overall architecture
You may stub out the db and redis dependencies with type-compatible interfaces. The TypeScript code should be complete and illustrate the full computation pipeline.
{
"context": "Tests whether the agent correctly implements multi-source recommendation scoring with specific weights, category diversity constraints, popular-item fallback, A/B test assignment via MD5 hash, correct A/B metrics and graduation criteria, serendipity slots, and privacy/GDPR opt-out as specified by the personalization skill.",
"type": "weighted_checklist",
"checklist": [
{
"name": "PDP signal weight 2.0",
"max_score": 7,
"description": "When the current product context (PDP) is used, similar-item scores are multiplied by 2.0 (not 1.0, 1.5, or 3.0)"
},
{
"name": "Recent-views signal weight 1.0",
"max_score": 7,
"description": "Scores from items similar to recent views are multiplied by 1.0 (no additional multiplier beyond the similarity score itself)"
},
{
"name": "Category affinity signal weight 0.1",
"max_score": 7,
"description": "Category-affinity-based candidate scores are multiplied by 0.1 (not 0.5, 1.0, or omitted)"
},
{
"name": "Recent views scope: top 10",
"max_score": 7,
"description": "Only the most recent 10 viewed products are used as seeds when sourcing candidates from recent views (not all views, not 5 or 20)"
},
{
"name": "Category scope: top 5",
"max_score": 6,
"description": "Only the top 5 categories by affinity score are used when generating category-based candidates (not top 3 or top 10)"
},
{
"name": "Exclude viewed and cart items",
"max_score": 7,
"description": "The final ranked list filters out products that appear in the user's recentViews AND products currently in the cart"
},
{
"name": "Popular-items fallback",
"max_score": 7,
"description": "When fewer personalized candidates than the requested limit exist, the result is topped up from a popular-products list"
},
{
"name": "Max 4 items per category diversity",
"max_score": 8,
"description": "The recommendation result enforces a maximum of 4 items from any single category (not 3 or 5 or unconstrained)"
},
{
"name": "20% serendipity slots",
"max_score": 7,
"description": "Approximately 20% of recommendation slots are reserved for serendipity (trending, new arrivals, or items from unexplored categories)"
},
{
"name": "MD5 hash for A/B assignment",
"max_score": 8,
"description": "The experiment.ts module uses MD5 hashing of userId to assign users to variants deterministically (not random, not SHA-256)"
},
{
"name": "50/50 experiment split",
"max_score": 7,
"description": "The A/B assignment splits users 50/50 into 'control' and 'personalized' variants (bucket < 50 = control)"
},
{
"name": "A/B metrics: CVR, AOV, RPV",
"max_score": 7,
"description": "design-notes.md mentions tracking conversion rate, average order value (AOV), and revenue per visitor as the primary A/B test metrics"
},
{
"name": "Graduation criteria: p<0.05 and 2+ weeks",
"max_score": 7,
"description": "design-notes.md states that personalization graduates to 100% only when p < 0.05 statistical significance is achieved over at least 2 weeks"
},
{
"name": "Privacy opt-out and data deletion",
"max_score": 8,
"description": "opt-out.ts implements user opt-out from personalization AND a GDPR-compliant user profile deletion function"
}
]
}
Personalized Recommendations API
Problem/Feature Description
NovaSport, an online sporting goods retailer, has recently launched a recommendation initiative. Their data team has already precomputed product similarity matrices (stored in Redis under similar:{productId}) and maintains live user profiles in Redis (user-profile:{key}) with recentViews (JSON array of {productId, ts}) and categoryScores (JSON object of category affinity). There is also a Redis sorted set popular-products and sets category-products:{categoryId} used for fallback. Anonymous users use the key anon:{sessionId}.
The engineering team now needs to build the recommendation serving layer — a function that takes a user context and returns a ranked list of product IDs to display. The function must work across different page contexts (homepage, product detail page, cart page), serve fresh personalized results quickly from precomputed data, and degrade gracefully when user history is sparse. The team is also cautious about rolling this out broadly and wants to measure actual business impact before fully committing.
Additionally, the team has noticed that early recommendation prototypes tended to show 10 similar running shoes when a runner visited — they want recommendations to feel broad and surprising, not just "more of the same." They also want to ensure compliance with privacy regulations as they expand to European markets.
Output Specification
Produce the following TypeScript files:
1. src/api/recommendations.ts — the main recommendation function that returns ranked product IDs, supporting homepage, PDP, and cart contexts
2. src/middleware/experiment.ts — an experiment assignment module that determines which variant a user should receive
3. src/privacy/opt-out.ts — a module that handles user opt-out and data deletion requests
4. design-notes.md documenting:
- How multiple recommendation signals are combined and weighted
- How diversity is enforced in the final result set
- How cold-start users are handled
- How the experiment is structured and what metrics should be tracked before graduation
- Privacy compliance mechanisms
You may stub out the Redis client. The code should be complete and illustrate the full serving and experiment assignment logic.
{
"name": "finsi/predictive-personalization",
"version": "0.1.0",
"summary": "Use machine learning models to predict customer preferences and dynamically personalize product recommendations, search results, and content across your store",
"skills": {
"predictive-personalization": {
"path": "SKILL.md"
}
}
}