Data retention
Last updated: 2026-09-11.
This page describes how long VIBE Search and Discovery (“VIBE”) keeps each category of data and how that data is deleted. The schedule mirrors the retention logic enforced in the application’s background worker. It is published for merchants and reviewers and is referenced from the Privacy policy.
Summary
Section titled “Summary”VIBE runs an automated retention job every week that permanently deletes data which has passed the retention period for its category. These are age thresholds, applied at the next scheduled run; weekly cleanup can add up to seven days and hourly cleanup up to one hour during normal operation. Outages can delay a run, and failed work is retried. Retention is applied per data type, not per merchant request. The same periods apply to all stores.
An additional hourly minimization sweep removes unmatched order lifecycle records once their 48-hour reordering window expires. Independent privacy maintenance every 15 minutes removes expired order-job payloads even when no new orders arrive, and requeues failed shop deletions.
Separately, uninstall and Shopify shop/redact requests trigger deletion of the installation’s data, subject to the trial-record and internal-audit exceptions below. See Deletion on uninstall and shop redaction.
Retention schedule
Section titled “Retention schedule”| Data category | What it contains | Retention period | Deletion rule |
|---|---|---|---|
| Search events | Per-search records: visit identifier, search text, result count and returned product ids, source surface, clicked product and rank, time to click, filters and Explore control values, matched result rules, A/B group, response time, and, when an order is matched, the Shopify order id, attributed product id, original and current matched revenue, match label, and attribution identifier. Stored only when the shopper allows analytics. | 90 days | Records older than 90 days, by creation date |
| Product impressions | Which products were shown for a search, in what position, and for how long, with the visit identifier and search text. Stored only when the shopper allows analytics. | 90 days | Records older than 90 days, by creation date |
| Order analytics lifecycle records | Minimal records used to apply refunds and cancellations idempotently: webhook delivery id, Shopify order id, event type, refunded product ids and amounts, and whether the order matched VIBE attribution. No customer, address, note, or payment fields. | 48 hours when unmatched; 90 days when matched | An unmatched record is deleted after 48 hours. Once its order is linked to retained VIBE attribution, it is marked as matched and deleted 90 days after creation. Matching customer redaction and store deletion remove it sooner |
| Shop events, general | Operational records for a store in the categories sync, webhook, auth, config, and support. | 90 days | Records older than 90 days, by creation date |
| Shop events, billing and error | Billing-related and error records, kept longer for accounting and diagnostics. | 1 year | Records older than 1 year, by creation date |
| Merchant email delivery records | One record per operational email sent to the merchant: recipient, subject, delivery status, provider message id, and any error. | 90 days | Records older than 90 days, by creation date. Also deleted with the store’s data |
| Redacted order markers | Order ids from customers/redact requests, kept so a late paid-order notification can never re-link search activity to those orders. | 90 days | Records older than 90 days, by creation date |
| Daily analytics | Per-store, per-day aggregates: total searches, unique visits, clicks, cart adds, conversions, revenue, distinct order-session counts, top searches, top no-result searches, top clicked products, and related summaries. No visit or order identifiers. | 3 years | Records older than 3 years, by report date |
| Monthly billing records | Per-store, per-month usage and billing summary: plan, visit allowance, visits used, overage, and charge status. | 3 years | Records older than 3 years, by billing month |
| Closed billing usage periods | Monthly visit and search totals, approved allowance, subscription context, and opening counters recorded when metering starts. No visit identifiers. | 3 years | Closed periods older than 3 years, by billing month |
| Active billing visits | A store-specific hash of the visit identifier, visit start, and last activity. Used to avoid counting the same visit twice across servers. No raw identifier or IP address. | 24 hours after last activity | Removed by an hourly job; also deleted with the store’s data |
| Shopify admin sessions | Session records required by Shopify’s app framework, including encrypted access and refresh tokens. Online sessions include the staff member’s user id, name, and email. | Until expired | Online sessions past their expiry, and offline sessions past their expiry whose refresh token is missing or has also expired. All of a store’s sessions are deleted on uninstall and on shop redaction |
| Customer privacy requests | The request id, customer id, and order ids from a customers/data_request (encrypted), plus the prepared result (encrypted). | See below | See Customer privacy requests |
| Verified store owner record | The store owner’s Shopify user id and encrypted email, used to notify the owner about privacy request results. | Life of the installation | Deleted with the store’s data |
| Product and search performance metrics | Rolling per-product and per-search counts (impressions, clicks, cart adds, orders, revenue) used for ranking and the merchandising reports. Aggregated, no visit identifiers. | Life of the installation | Deleted with the store’s data |
| Store configuration and search index | Settings, widget configuration, Explore controls, result rules, exclusion rules, search configuration, encrypted tokens and storefront password, VIBE’s copy of the catalog, and the per-store search index. | Life of the installation | Deleted with the store’s data |
| Trial record | The store domain and the date of the first free trial. | Kept | Not removed by the uninstall or shop redaction cleanup, so a free trial is not granted twice |
| Internal staff audit log | Actions taken by VIBE staff in the internal operations panel: staff user, action, path, IP address, and a scrubbed copy of the request data. | 1 year | Records older than 1 year, by creation date |
| Internal staff device records | Trusted-device tokens (30 days) and login verification codes (10 minutes) for VIBE staff. | Until expired | Expired rows are removed by the weekly job |
Daily analytics remains after its source records are deleted because it contains no visit or order identifiers. That privacy boundary also means a refund or cancellation received after the matched search event’s 90-day retention period cannot be connected back to, or retroactively removed from, the older daily aggregate. Legacy control-group attribution created before VIBE stored line-level product ids cannot be matched safely to a refunded product line unless an attributed product id was already recorded.
Cache and queue entries
Section titled “Cache and queue entries”These entries live in Redis. Cache entries use expiration times; jobs are removed on completion, after exhausted retries, or by scheduled cleanup as specified below. A paused or unavailable worker can retain pending work longer than its normal retry schedule.
| Entry | What it contains | Kept for |
|---|---|---|
| Per-minute request counters | A counter per shopper IP address and endpoint | About 65 seconds |
| Abuse-guard counters | A counter of new billable visits per shopper IP address per day, and per store per hour | 24 hours (per IP) and 1 hour (per store), plus 5 seconds |
| Recently ordered product markers | Store id and product id from a paid order | 60 seconds |
| Order attribution jobs | Order id, product ids and handles, prices, quantities, and the cart attribution identifier from a paid order | Eligible for deletion 24 hours after completion or 7 days after failure; swept every 15 minutes, or earlier under queue count limits. Pending/retrying jobs remain until processing ends or shop deletion removes them. Outages can delay the sweep |
| Search-event capture recovery jobs | A failed or slow direct write of a consented search event: the same random event id and event time, pseudonymous visit identifier, source surface and A/B group, raw search text, result count and response time, semantic and Explore controls, filters, matched rules, and returned product and variant ids with their positions | Up to 12 attempts with 60-second exponential backoff (about 34 hours to the last scheduled attempt). The payload is deleted immediately after a successful attempt or after the final failed attempt; exhausted failures are not retained |
| Search text embeddings | The numeric representation of a search phrase, stored under a hash of the phrase. The phrase itself is not stored | 1 year |
| Rendered product cards and section shells | Product card HTML rendered by the store’s theme | 7 days |
| Explore control cache | Derived control values for the catalog | 24 hours |
| Price cache | Current prices for rendered cards | 30 minutes |
| Contextual variant prices | Exact variant amount, currency, country and an opaque buyer/location partition, where applicable | 60 seconds; expired values are never served |
| B2B authorization and eligibility | Store-specific keyed hashes of customer/location context, authorization decisions and product eligibility; raw customer and company-location IDs are not stored in these cache entries | 60 seconds; also invalidated by relevant B2B webhooks |
| Your Vibe recommendation groups | Group titles, source-product references and recommended products, under the store ID and a hash of favorite-product references; no visit or attribution identifier | 6 hours for internal requests without a market filter. Market-specific storefront requests bypass this cache |
| Storefront session cookie | The cookie obtained with the merchant’s storefront password, for password-protected stores | 23 hours |
| Shop deletion jobs | Internal shop ID, shop domain, reason and uninstall timestamp when applicable | Failed deletion requests remain until retried and completed; privacy maintenance retries them every 15 minutes. Successful jobs have a bounded count history |
| Privacy request queue entries | The internal request id only | Removed on completion or after five exhausted attempts. The durable PostgreSQL request row remains, and the hourly sweep requeues unfinished requests |
Customer privacy requests
Section titled “Customer privacy requests”A customers/data_request is recorded durably and processed in the background. The result is encrypted at rest and downloaded by the verified store owner from Customer privacy in the app.
- The prepared result expires 7 days after it is ready. An expired result is deleted, and the owner can prepare a new one from the same page while the request context is retained.
- If the owner notification has not yet succeeded when a result expires, VIBE prepares the result again automatically so the request can still be completed.
- 30 days after the result is downloaded, the encrypted request context and result are erased. A minimal completion record remains.
- 90 days after the result is downloaded, the completion record is deleted.
- Requests that have not been completed stay on file so they can be completed.
- A
customers/redactrequest deletes matching search, impression, and order lifecycle records; removes the redacted order ids from any pending request context; and invalidates prepared results. Before deletion, VIBE advances a per-store analytics high-water barrier 65 seconds beyond the request time. Direct and queued search-event inserts at or before that barrier are rejected, preventing pre-redaction analytics from being recreated after deletion, including events carrying the accepted one minute of future client-clock skew. - All of a store’s privacy requests and the verified owner record are deleted with the store’s data.
Purge cadence and schedule
Section titled “Purge cadence and schedule”The retention purge runs as a scheduled background job:
- Frequency: weekly
- Schedule: every Sunday at 03:00 UTC
- Job: the
data-cleanupworker’sretention_purgetask
The same worker runs order_lifecycle_pending_purge hourly (at minute 23) to remove lifecycle deliveries older than 48 hours which never matched VIBE attribution. It also runs privacy_maintenance every 15 minutes to purge completed/failed order jobs beyond their respective thresholds and retry failed shop deletions.
Each run deletes every record that has passed its retention period for every category in the table above, in a single pass. It also applies the privacy request expiry rules. A separate hourly sweep applies the privacy request expiry rules and retries unfinished requests.
Deletion on uninstall and shop redaction
Section titled “Deletion on uninstall and shop redaction”The retention schedule above governs routine, age-based deletion. A separate path removes the installation’s data:
- Uninstall. VIBE deletes the store’s Shopify sessions immediately and schedules deletion for 30 days later as a fallback. Reinstallation cancels that pending uninstall timer only while the original data still exists. It does not restore deleted data.
- Shop redaction (
shop/redact). Shopify normally sends this request 48 hours after uninstall. VIBE deletes the store’s sessions and privacy request records immediately and starts a priority deletion job, which is not cancelled by reinstallation. There is no guaranteed 30-day recovery period.
Full deletion removes the store’s search index and the store’s database record, which cascades to all related search events, product impressions, analytics, metrics, rules, controls, search configuration, email delivery records, and billing records. It also removes any remaining sessions and email delivery records keyed by the store domain. The trial record and internal staff audit records are not removed by the shop cascade; they follow the schedule above.
Before removing the search index and database record, cleanup takes the catalog-write lease, waits for active shop jobs to finish, removes the installation’s pending and retained queue jobs, and clears its Redis caches, including buyer authorization, contextual prices, recommendation groups and storefront cookies. A failed cache or queue operation does not count as completed deletion. Temporary conflicts are deferred; failed deletions are requeued by privacy maintenance.
Global search-text embeddings contain no shop or visit identifier and follow their one-year cache lifetime. Legacy hashed Explore-control cache entries created before shop-specific cache keys were introduced are no longer read and expire within their existing 24-hour lifetime. Non-identifying internal request IDs in privacy jobs are removed when those jobs finish.
Where this is enforced (for reviewers)
Section titled “Where this is enforced (for reviewers)”- Retention logic and periods:
worker/src/workers/data-cleanup.ts, functionpurgeExpiredData. - Privacy request expiry:
packages/shared/src/privacy-requests.ts, functionexpirePrivacyData. - Schedule registration:
worker/src/index.ts, the weeklyretention-purge, hourlyorder-lifecycle-pending-purge, and hourlyprivacy-request-sweepjobs. - Cache lifetimes:
packages/shared/src/cache/redis.tsandpackages/shared/src/rate-limit.ts. - Queue lifetimes:
packages/shared/src/queues.tsandpackages/shared/src/queue-retention.ts. - Shop queue/cache deletion:
packages/shared/src/shop-data-cleanup.ts. - Session credential encryption and legacy backfill:
packages/shared/src/shopify-session-storage.ts.
Hosting and contact
Section titled “Hosting and contact”VIBE’s application services run on hosted infrastructure. The providers listed on the Sub-processors page may process data in the regions described by their own terms, data processing agreements, and sub-processor notices.
Questions about data retention or deletion can be sent to support@coi.se.