Bee for Craft CMS

The catalog

A source is "these elements become Recombee items, with these properties". It answers three questions: which elements, which of them count, and what Recombee is told.

Which elements

Element typeScoped by
EntrySections, and entry types within them
CategoryCategory groups
AssetVolumes
UserUser groups
Product (Commerce)Product types
Variant (Commerce)Product types

Leave the scope boxes unchecked to include everything of that type. One database can carry several sources — the itemType property Bee always sends keeps them apart.

Which of them count

Live elements only is on by default and should usually stay on. Disabled, expired and pending elements are removed from Recombee rather than left behind. An item that is still in the database is an item that can still be recommended, and the first symptom of getting this wrong is a rail promoting something that was unpublished an hour ago.

Where sources live

Sources are stored in project config, not in a database table, because which entry types feed the recommender is a deployment concern. They travel with a deploy rather than needing to be re-clicked in every environment.

The consequence is correct but surprising the first time: sources are read-only when allowAdminChanges is off. On production you change them by deploying a changed project config.

Item IDs

ElementID
Entry 42e42
Product 42p42
Variant 42v42
Category 42c42
Asset 42a42

As soon as more than one site is synced the site ID joins them: e42-s2 — two items, with their own titles, URLs and properties, which is correct, because they are different things to recommend.

Changing which sites are synced changes every item ID. The old IDs stay behind in Recombee along with the interaction history attached to them. Run bee/sync/catalog --force and then bee/sync/purge. Diagnostics will tell you if this has happened.

Properties Bee always sends

title, url, imageUrl, itemType, siteId, sourceHandle, slug, enabled, postDate, expiryDate, updatedAt.

These are not optional and you cannot redeclare them. Every recommendation request is filtered on enabled, postDate and expiryDate, because the catalog is push-based and can lag.

Mappings

Each mapping is a Recombee property name, a type, and where to read it from:

Read fromValue
Custom fieldA field handle
Element attributetitle, slug, postDate, url, …
Built-in mapperOne of the keys below
TwigAn object template, e.g. {{ object.author.fullName }}

Built-in mappers

image, images, author, categories, categoryIds, tags, wordCount, readingMinutes, ancestors, kind.

And the Commerce family: commerce:price, commerce:promotionalPrice, commerce:onSale, commerce:sku, commerce:stock, commerce:inStock, commerce:productType, commerce:variantCount, commerce:variantSkus, commerce:minPrice, commerce:maxPrice, commerce:weight, commerce:productId.

Types

Values are coerced to the declared type and dropped if they cannot be. A property declared double that receives "12.00" would otherwise get the whole item rejected by Recombee.

Recombee has one property namespace per database. Two sources that both send price have to agree on its type. Bee reports the disagreement on the catalog screen and fails the diagnostics check rather than letting the second source silently break the first.

Recombee needs a property to exist before an item can carry it. Press Sync item properties, or run php craft bee/sync/properties.

Syncing

Elements are pushed when saved, removed when unpublished or deleted, and re-sent in bulk from the console.

Content fingerprints. Bee stores a hash of the payload it last sent, per element and per site, and sends nothing if it matches. That is what makes bee/sync/catalog safe in a deploy script: on an unchanged catalog it is a table scan and no HTTP at all.

One queue job, not ten thousand. Element saves are collected during the request and flushed into a single queue job at the end of it. A job per save would turn a bulk resave of ten thousand entries into ten thousand jobs.

Batching. Bulk syncs go through Recombee's batch endpoint. The response carries one result per sub-request and Bee reads them back individually, so one bad item is one failure rather than quietly taking the rest of the batch with it.

StatusMeans
syncedSent and acknowledged. The fingerprint is current.
pendingQueued, not yet sent.
failedRecombee refused it. The reason is on the row and in the log.
deletedRemoved, because it stopped matching a source or was unpublished.

Console

php craft bee/sync/catalog                    # sync every source
php craft bee/sync/catalog --force            # re-send even unchanged items
php craft bee/sync/catalog --source=Products  # one source
php craft bee/sync/catalog --dry-run          # build and log, send nothing
php craft bee/sync/properties                 # create declared item properties
php craft bee/sync/element 1234               # one element
php craft bee/sync/purge                      # delete excluded and failed items

Force a re-sync after changing a property mapping, after changing which sites are synced, or after pointing Bee at a different database. It is not destructive: Set Item Values is an upsert.

Previewing a payload

The catalog screen has a payload preview for any element, built by the same method the sync, the save handler, the queue job and the console all use — so it is the payload rather than an approximation of it. Use it before a first sync.