How you set up Social Insights depends on the network, as they behave differently:
-
Facebook: connect your account, and Piano collects your data automatically.
-
X: send your X data to Piano yourself. There is no account connection for X.
You can also, optionally, tag your posts with utm_pid to link your social data to your on-site Piano Analytics data. Once your data is flowing, see Reading your Social Insights board and the Social Insights data model.
Facebook setup
To set up Facebook, connect your Facebook account(s). Contact your Account Manager or the support team, and they will send you a link that grants Piano the right delegation to your account.
Once the delegation is in place, Social Insights automatically collects your Facebook data and populates your board. There is nothing else for you to send or maintain.
X setup
X works differently from Facebook: there is no account connection, and Piano cannot retrieve X data on your behalf because of X API licensing restrictions. To bring X data into your board, you send your data to Social Insights yourself, using the method below. If you do not publish to X, you can skip this section.
By following the instructions below, you can send the required data to the right place. From there, our data model takes care of the rest: calculating the metrics and merging your X data correctly with your Facebook and other analytics datasets.
The integration consists of two types of data, catalogs and measurements, which you can send at whatever frequency works best for you. Once received, our data model processes this data, calculates the metrics, and makes all the resulting information available in the board.
The metric keys you send for X (m_soi_x_post_* and m_soi_x_handle_*) are the raw X measurement keys. They are mapped into the unified metrics of the Social Insights data model (m_soi_post_*), which is why the names differ.
Catalogs
Two catalogs must be configured to collect metadata:
|
Catalog name |
Import keys |
Associated properties to send |
|---|---|---|
|
soi_handle |
soi_handle_id |
soi_post_network, soi_handle_url, soi_handle_name |
|
soi_post |
soi_post_id |
soi_post_creation_date, soi_post_message, soi_post_url |
Catalog mapping: soi_handle
This catalog collects handle-level metadata.
|
Parameter in X API |
Property key |
Type |
Data transformation |
Comment |
|---|---|---|---|---|
|
Id |
soi_handle_id |
KEY |
|
|
|
- |
soi_post_network |
VALUE |
Yes |
Constant: "X" |
|
username |
soi_handle_name |
VALUE |
|
|
|
soi_handle_url |
VALUE |
Yes |
Reconstruct using the username: https://x.com/{username} |
Example request:
curl -X POST 'https://analytics-api-eu.piano.io/import/v1/catalogs/batch' \
-H 'Content-Type: application/x-ndjson' \
-H 'x-api-key: <API_KEY>' \
-H 'x-pa-orga-code: <ORGA_CODE>' \
--data-binary @- <<'EOF'
{
"import_id": "<HANDLES_CATALOG_ID>",
"import_keys": {
"soi_handle_id": "<SOI_HANDLE_ID>"
},
"associated_properties": {
"soi_post_network": "X",
"soi_handle_name": "<HANDLE_USERNAME>",
"soi_handle_url": "https://x.com/<HANDLE_USERNAME>"
}
}
EOF
Catalog mapping: soi_post
This catalog collects post-level metadata.
|
Parameter in X API |
Property key |
Type |
Data transformation |
Comment |
|---|---|---|---|---|
|
id |
soi_post_id |
KEY |
Yes |
utm_pid querystring parameter in the text content if a URL parameter is available, otherwise id |
|
created_at |
soi_post_creation_date |
VALUE |
|
|
|
text |
soi_post_message |
VALUE |
|
|
|
- |
soi_post_url |
VALUE |
Yes |
Reconstruct from: https://x.com/{author_username}/status/{id} |
Example request:
curl -X POST 'https://analytics-api-eu.piano.io/import/v1/catalogs/batch' \
-H 'Content-Type: application/x-ndjson' \
-H 'x-api-key: <API_KEY>' \
-H 'x-pa-orga-code: <ORGA_CODE>' \
--data-binary @- <<'EOF'
{
"import_id": "<POSTS_CATALOG_ID>",
"import_keys": {
"soi_post_id": "<SOI_POST_ID>"
},
"associated_properties": {
"soi_post_creation_date": "2026-03-20 14:32:10",
"soi_post_message": "Check our latest race highlights https://example.com/race?utm_pid=<SOI_POST_ID>",
"soi_post_url": "https://x.com/<HANDLE_USERNAME>/status/<TWEET_ID>"
}
}
EOF
Measurements
Measurements carry the KPI data itself. There are two measurements to send at regular intervals, and both support hourly granularity if you need it.
|
Measurement key |
Level |
Categories |
Property key |
Granularity |
Visibility |
|---|---|---|---|---|---|
|
soi_x_handle |
Site |
Social Insights |
soi_handle_id |
Hour |
hidden |
|
soi_x_post |
Site |
Social Insights |
soi_handle_id, soi_post_id |
Hour |
hidden |
soi_x_handle measurement detail
|
X API field |
Value key |
Metric key |
Type |
Comment |
|---|---|---|---|---|
|
- |
- |
- |
Time period |
Current hour time slot in site timezone |
|
public_metrics.followers_count |
followers |
m_soi_x_handle_follower |
int |
|
|
id |
soi_handle_id |
|
Property key |
|
|
- |
site_id |
|
Property key |
Constant: your PA site id |
Example request:
curl -X POST 'https://analytics-api-eu.piano.io/import/v1/measurements/batch' \
-H 'Content-Type: application/x-ndjson' \
-H 'x-api-key: <API_KEY>' \
-H 'x-pa-orga-code: <ORGA_CODE>' \
--data-binary @- <<'EOF'
{
"key": "soi_x_handle",
"period": "<PERIOD>",
"site_id": <SITE_ID>,
"values": {
"followers": 1523
},
"properties": {
"soi_handle_id": "<SOI_HANDLE_ID>"
}
}
EOF
soi_x_post measurement detail
|
X API field |
Value key |
Metric key |
Type |
Comment |
|---|---|---|---|---|
|
- |
- |
- |
Time period |
Current hour time slot in site timezone |
|
non_public_metrics.impression_count |
views |
m_soi_x_post_views |
int |
|
|
public_metrics.like_count |
likes |
m_soi_x_post_likes |
int |
|
|
public_metrics.reply_count |
comments |
m_soi_x_post_comments |
int |
|
|
public_metrics.retweet_count |
shares |
m_soi_x_post_shares |
int |
|
|
public_metrics.quote_count |
quotes |
m_soi_x_post_quotes |
int |
|
|
public_metrics.bookmark_count |
bookmarks |
m_soi_x_post_bookmarks |
int |
|
|
non_public_metrics.url_link_clicks |
link_clicks |
m_soi_x_post_link_clicks |
int |
|
|
non_public_metrics.user_profile_clicks |
profile_clicks |
m_soi_x_post_profile_clicks |
int |
|
|
|
Clicks |
|
int |
non_public_metrics.url_link_clicks + non_public_metrics.user_profile_clicks |
|
media_public_metrics.view_count |
video_views |
m_soi_x_post_video_views |
int |
|
|
|
posts |
m_soi_x_post_posts |
int |
Constant: 1 |
|
media_non_public_metrics.playback_0_count |
playback_start |
m_soi_x_post_playback_start |
int |
|
|
media_non_public_metrics.playback_25_count |
25_video_play |
m_soi_x_post_25_video_play |
int |
|
|
media_non_public_metrics.playback_50_count |
50_video_play |
m_soi_x_post_50_video_play |
int |
|
|
media_non_public_metrics.playback_75_count |
75_video_play |
m_soi_x_post_75_video_play |
int |
|
|
media_non_public_metrics.playback_100_count |
video_complete |
m_soi_x_post_video_complete |
int |
|
|
author_id |
soi_handle_id |
|
Property |
|
|
|
soi_post_id |
|
Property |
utm_pid in the text content if a URL parameter is available, else id |
|
|
site_id |
|
Property |
Constant: your PA site id |
Example request:
curl -X POST 'https://analytics-api-eu.piano.io/import/v1/measurements/batch' \
-H 'Content-Type: application/x-ndjson' \
-H 'x-api-key: <API_KEY>' \
-H 'x-pa-orga-code: <ORGA_CODE>' \
--data-binary @- <<'EOF'
{
"key": "soi_x_post",
"period": "<PERIOD>",
"site_id": <SITE_ID>,
"values": {
"views": 29435,
"likes": 26,
"comments": 13,
"shares": 3,
"quotes": 0,
"bookmarks": 1,
"link_clicks": 456,
"profile_clicks": 15,
"clicks": 471,
"video_views": 0,
"posts": 1,
"playback_start": 0,
"25_video_play": 0,
"50_video_play": 0,
"75_video_play": 0,
"video_complete": 0
},
"properties": {
"soi_handle_id": "<SOI_HANDLE_ID>",
"soi_post_id": "<SOI_POST_ID>"
}
}
EOF
Link your social data to Piano Analytics (optional)
This step is optional. It lets you connect your Social Insights data to your on-site Piano Analytics data. Without it, both datasets still work, they simply remain separate.
Social Insights measures how your content performs on social networks: views, likes, shares, and engagement at both the post and handle level. But for brands, the story does not end at the post. The real value often lies in what happens after the click: the traffic, engagement, subscriptions, and revenue that your social posts drive on your site.
Piano Analytics already measures all of this on-site activity. What was missing was a reliable way to connect a visit back to the exact post that generated it. That is what this section covers: how Social Insights and Piano Analytics data are combined through a dedicated UTM parameter, utm_pid, to give you a complete view of social performance, from publication through to conversion.
What utm_pid unlocks
utm_pid is a Piano Analytics UTM parameter set at the post level. It lets you combine social network data with Piano Analytics data, so you can see how a post performed alongside what happened on your site after the click. Specifically, utm_pid unlocks:
-
Visits, page views, and engagement generated by a specific post, handle, or network.
-
Conversions, subscriptions, and revenue attributable to a post.
-
On-site behavior of social audiences: whether they bounce, engage, or convert.
Add utm_pid to your posts
To connect a post to the on-site activity it drives, the utm_pid parameter must be part of the outbound link at the time you publish the post. Here is how:
-
Generate a unique identifier for the post (for example, an internal content ID, a CMS ID, or any unique string).
-
Append it to the article URL alongside your other UTM parameters before pasting the link into your social media publishing tool:
https://www.example.com/article-slug?utm_source=facebook&utm_medium=social&utm_pid=123
-
Publish the post. Social Insights detects the
utm_pidin the post's outbound link and uses it as the post ID (soi_post_id). Visitors who click through carry the same ID into Piano Analytics, completing the link between the post and their on-site activity.
If you use a social publishing tool, tagging can be automated: configure the tool's link tracking settings to append utm_pid with a unique value to every published link. This removes the manual step and keeps your tagging consistent across every post.
-
The parameter can also be detected if it appears as a URL parameter within the post's message text, but placing it in the outbound link is the recommended approach.
-
Facebook preserves URL query strings on link posts, so the parameter arrives intact on your site.
Recommendations
-
Use a unique identifier per post. The
utm_pidvalue becomes the post ID in Piano Analytics. Reusing the same value across multiple posts merges their data together. -
utm_pidworks alongside your existing campaign parameters (utm_source,utm_medium, and so on) without conflict. -
Keep values short, unique, URL-safe, and consistent in format to avoid tagging errors.