We’ve migrated our documentation to a new site, which means some URLs have changed. Please visit the new documentation site here.

Setting Up Social Insights

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



https://x.com/{username}

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:

CSS
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:

CSS
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:

CSS
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

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:

  1. Generate a unique identifier for the post (for example, an internal content ID, a CMS ID, or any unique string).

  2. 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
  1. Publish the post. Social Insights detects the utm_pid in 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_pid value becomes the post ID in Piano Analytics. Reusing the same value across multiple posts merges their data together.

  • utm_pid works 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.