Skip to content

Recommendations

Requires a license with the recommendations feature. See pricing.

Recommendations learns from what signed-in readers do with your entries: what they view, like, share and bookmark. From that it answers three questions: which entries are similar to this one, which are trending, and what this reader should see next. Scores are recomputed when you ask, from the console or from your own scheduler.

StepWhat happens
RecordYour front end reports each action a reader takes on an entry, with the reader's own token.
RecomputeA super admin runs a recompute. It pairs entries the same readers acted on in the last 30 days and ranks the last seven days' activity for trending.
ReadYour front end asks for similar entries, trending entries or the reader's feed, and gets entry ids back. Read the entries through the Content API to show them.

Each action counts toward a reader's feed with its own weight:

ActionWeight
view1
like2
share3
bookmark5

You need a token in TOKEN for a super_admin, which also counts as a reader here. The quickstart shows how to get one. Put the ids of two entries in A and B.

  1. Record that you liked both entries:

    Terminal window
    curl -X POST http://localhost:3002/api/v1/recommendations/behavior \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"content_id\": \"$A\", \"action\": \"like\"}"
    curl -X POST http://localhost:3002/api/v1/recommendations/behavior \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"content_id\": \"$B\", \"action\": \"like\"}"

    Each answers 201 with the recorded id, user_id, content_id, action and created_at.

  2. Recompute the scores:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/recommendations/refresh \
    -H "Authorization: Bearer $TOKEN"
    { "similarity_pairs_computed": 1, "trending_items_computed": 2, "feeds_generated": 0, "duration_ms": 9 }
  3. Ask what is similar to the first entry:

    Terminal window
    curl "http://localhost:3002/api/v1/recommendations/similar?content_id=$A&limit=5" \
    -H "Authorization: Bearer $TOKEN"
    { "similar": ["<B>"] }
  4. Read the trending list:

    Terminal window
    curl "http://localhost:3002/api/v1/recommendations/trending?limit=10" \
    -H "Authorization: Bearer $TOKEN"

    The answer is {"items": [...]}, each with content_id, score and view_count.

  5. Open Settings, then Recommendations, in the admin console. Trending now lists both entries.

POST /api/v1/recommendations/behavior takes content_id, an entry's id, and action, one of view, like, share or bookmark. Send it with the reader's own token, so the action is recorded against them. Any signed-in caller may record.

Every route under /api/v1/recommendations needs a signed-in caller. Each answers entry ids.

To showCallAnswer
Entries similar to one entryGET /api/v1/recommendations/similar?content_id=<id>{"similar": ["<id>", ...]}. limit is 10 by default, at most 100.
What is trendingGET /api/v1/recommendations/trending{"items": [{"content_id", "title", "slug", "score", "view_count"}]}, up to the top 100. limit is 20 by default. title and slug are empty, so read the entry for them.
The caller's feedGET /api/v1/recommendations/feed{"entries": [{"content_id", "score", "source", ...}], "total": n}. limit is 20 by default, at most 100, and offset at most 10000.

Two entries are similar when the same readers acted on both in the last 30 days, with any action, a view included. A feed entry's source is similar, for an entry close to one the reader acted on, or collaborative, for one other readers with the same taste liked. The feed is built when it is requested, from the scores of the last recompute. A limit or offset above its maximum is lowered, not refused.

Recompute after a batch of activity, or call the refresh route on a timetable from your own tooling, signed in as a super admin. In the console, a super admin chooses Recompute under Settings, then Recommendations. Only one recompute runs at a time, and a second answers 409.

Each reader is put in the recommendation group or the random group, at random, the first time they call GET /api/v1/recommendations/ab-test, and stays there:

{ "bucket": "recommendation", "recommendation_pct": 50.4, "random_pct": 49.6, "total_users": 1250 }

The group is a label your front end reads. LyEve serves the same answers to both groups, so show recommendation blocks only to readers in recommendation, and compare how the two groups engage. A reader who never calls ab-test is in neither group. GET /api/admin/recommendations/ab-stats returns recommendation_count, random_count, total_users, recommendation_pct and random_pct.

Recommendations have no settings of their own. If you set LYEVE_PLUGINS to choose which features start, include recommendations in it. See licensing and tiers.

The admin routes take a signed-in session. An admin token cannot call them.

Recommendation routes
MethodPathRolePurpose
POST/api/v1/recommendations/behaviorsigned inRecord a view, like, share or bookmark.
GET/api/v1/recommendations/similarsigned inEntries similar to content_id.
GET/api/v1/recommendations/trendingsigned inTrending entries.
GET/api/v1/recommendations/feedsigned inThe caller's feed.
GET/api/v1/recommendations/ab-testsigned inThe caller's group and the split.
GET/api/admin/recommendations/ab-statsadminGroup counts and percentages.
POST/api/admin/recommendations/refreshsuper_adminRecompute every score.
POST/api/admin/recommendations/generate-feed/{userID}super_adminBuild and return one user's feed.

Without a license that carries recommendations, the routes answer 404. A license that lapses while the instance runs makes them answer 402 payment_required.

Every error these routes return
StatusMessageCause
400content_id is required, action is requiredA field is missing.
400invalid actionThe action is not view, like, share or bookmark.
400invalid JSON bodyThe body is not JSON, or content_id is not a UUID on behavior.
400invalid content_idcontent_id is not a UUID on similar.
400invalid user IDThe id in generate-feed is not a UUID.
401authentication requiredThe caller is not signed in.
402payment_requiredThe license lapsed while the instance ran.
409a refresh is already in progressA recompute is still running.
503recommendations is not availableThe feature is not ready.