For information about how REST API works, see rest main page.
For a site that renders its own pages - Next.js, a mobile app, any server - instead of letting the Personyze tag change them. You ask for one page of one visitor and get that visitor's Personal pages words as data: the hero's headline, the line under it, its picture and button words, the message bar, the badge on a pricing plan. They are chosen exactly as the tag would choose them on that page: the visitor's segment from how they arrived, the version they are shown, and only versions you approved.
POST app.personyze.com/rest/personal_pages
Sign it with your account's API key (Integrations › API) - from your site's own server; a panel login is refused. The visitor id you send is your own id for the visitor; it chooses which version they see, and nothing else - it is not a login.
Request
| Field | Required | Meaning |
|---|---|---|
page_url |
yes | The full address of the page you are rendering, on your campaign's site. A path alone, or another site, is refused. |
visitor_id |
yes | Your own id for this visitor (up to 200 characters). Through one visit, the same id sees the same version, while the versions you approved and their weights stay as they are. |
session_start |
no | When this visitor's visit began, in seconds (Unix time) - milliseconds are refused. Without it, the visit is the UTC day. |
landing |
no | The visit's first page: url, referrer, utm_term. Without it, this page is the landing. The segment comes from these, as the tag's does. |
company |
no | What you know of the visitor's company: industry, size, name, revenue. Used when your campaign segments by company - the tag reads it from the visitor's profile; here only what you send counts. |
self |
no | The visitor's answer to "Tell us about you", when your site asked it itself: the words of the segment they chose. |
segment |
no | A segment you chose yourself, by its key: that segment's words, never held back, and no pages are read or versions written for it. One your account does not have is no segment. |
campaign_id |
no | Which Personal pages campaign, when you have more than one - a staging one too, to try it before it goes live. Without it, your newest live one. |
Example
curl -X POST 'https://api:FD09908F25BECB09D78EBEA1DADFB618651F612D@app.personyze.com/rest/personal_pages' \
-H 'Content-Type: application/json' \
-d '{"page_url": "https://www.example.com/products/routes", "visitor_id": "a3f9c2d1-7b4e", "landing": {"url": "https://www.example.com/solutions/logistics", "referrer": "https://www.google.com/"}}'
{
"segment": "logistics",
"campaign_id": 1096,
"held_back": false,
"pieces": [
{"kind": "hero", "templateId": 12, "version": 2, "selector": "#hero", "words": {"headline": "Ship every route on time", "subline": "Pages for logistics teams.", "image_url": "https://cdn.example.com/routes.jpg", "cta_text": ""}},
{"kind": "banner", "templateId": 14, "version": 1, "selector": "", "words": {"message": "Read how freight teams do it", "link_text": "Read", "link_url": "https://www.example.com/case/freight"}}
],
"cache": {"key": "/products/routes|logistics|12:2,14:1", "max_age": 60}
}
Response
| Field | Meaning |
|---|---|
segment |
The visitor's segment, "" for none. |
campaign_id |
The campaign that answered (0: none). |
held_back |
true when the visitor is in your campaign's original share - the comparison group. Show your own page; pieces is empty. |
pieces |
One per part of the page that changes: its kind, the templateId and version it was written for, selector (where the tag would put it on your page - a hint), and words. |
cache.key |
Two answers with the same key are the same answer: page, segment and each piece's version. |
cache.max_age |
Seconds you may keep the answer: a version you approve shows within it. 5 when your account could not be read in time - ask again soon. |
The words by kind:
| Kind | Words |
|---|---|
hero |
headline, subline, image_url, cta_text (only when you freed the hero's button); a hero you designed: headline, subline, button |
banner |
message, link_text, link_url |
pricing |
plan_name, badge, reason |
list_order |
order (the items' names, in the segment's order, as JSON) |
form |
heading, offer, send, lang |
header |
cta_text, link, lang |
booking |
heading, button, confirm_title, confirm_body, lang |
No Personal pages campaign, none live, or a page with nothing that changes for this visitor: pieces is empty - never an error. A word that is "" keeps your own. A piece with a lang is in that language: place it only on a page in it. Show a picture or a link only when its address starts with https://.
Your campaign's "Who it's for" rules (its Segments step) are not checked here - there is no visit to check them against, so the answer is for any visitor you ask about. Apply them yourself before you show the words.
At most 20 requests a second for one API key, on each of our servers; past that, 429. Keep answers for max_age seconds.
Results and conversions
Every visitor you ask about is counted in your campaign's Results beside the visitors the tag served: once a visit, for each piece they were given, or for the original when they were held back. A request with your own segment is a check and is not counted.
When a visitor converts - a sign-up, an order - tell us from the same server, with the same visitor_id, and the same session_start if you sent one:
POST app.personyze.com/rest/personal_pages/convert
{"visitor_id": "a3f9c2d1-7b4e", "session_start": 1800000000}
{"ok": true, "converted": 2}
converted is how many of the visit's pieces it was counted for - 0 when we served this visitor nothing in that visit (without session_start, that UTC day). Results count a conversion you report within two days of the visit; they show a day after it.
In the browser
On a page with the Personyze tag, every piece the tag is given also leaves its words for your own code - on window._S_T_PS_WORDS[kind], and in a personyze-words event. The tag often answers before your components mount, so read the global when they mount, and listen for what comes after:
const hero = window._S_T_PS_WORDS?.hero;
if (hero) myHero.setHeadline(hero.headline);
document.addEventListener('personyze-words', e =>
{ const {kind, segment, words} = e.detail;
if (kind == 'hero') myHero.setHeadline(words.headline);
});
If your page renders these parts itself (React, Next.js), add data-pz-words-only to its <html> element: the tag then changes nothing on the page and only hands you the words.