This functionality is in development. Meta can change or remove this functionality at any time.
Share extensions for Workplace allow people to share information safely and easily on Workplace, in a way that respects the privacy of the source material.
By supporting Share Extensions, you can ensure that your content previews correctly on Workplace, enable people to link folders with their Workplace groups, and provide your content in the groups composer on Workplace, making it easy to share recently created content right inside a group.
On Workplace, people often share links to internal company resources, which should only be viewable by certain people. This is in contrast to Facebook, where people commonly share public content, like news articles or blog posts.
In order for Workplace to generate a preview to company-private content, some metadata needs to be provided. As a provider, you can choose whether to provide metadata for the current viewer on Workplace, depending on whether they're allowed to view the content or not.
This document outlines the components of enabling Share Extensions. There are 3 key components:
This document also covers how to configure your app to add Share Extension support.
To set up your app for Share Extension support, you need to provide the following 3 fields:
example.com
) will also cover any subdomains (e.g. acme.example.com
).www.example.com/download?id=123
or www.example.com/file/456
but not www.example.com/blog
, you can use a regex such as \/(download?|file\/).+
//.*/
).Your app should also be set up to subscribe for the Link
webhook topic and the preview
, and should be enabled for the Link Unfurling permission.
As this is a beta feature, it's not currently possible to configure your app via the Developer Dashboard at developers.facebook.com.
Contact your assigned Meta Partner to configure or update these fields.
The main feature of share extensions is to make your content preview correctly on Workplace. This entails providing support for authenticated preview metadata in a format Workplace expects, such that when URLs to your content are shared, Workplace can fetch that metadata and create a preview. This process is often called link unfurling.
While Meta is able to get metadata to unfurl a public URL via the Open Graph protocol and the Facebook Crawler, this process is not possible for private URLs, which are more commonly shared into Workplace. Instead, when someone shares a private URL into Workplace, a webhook will be issued to a callback URL you define, and you'll be able to respond with a metadata payload describing the URL for the person sharing it, in order to render a link preview.
This same process will repeat for each person who views the shared URL on Workplace, allowing you to control the preview visibility on a per-user basis.
In order to enable authenticated previews, you'll need to configure your app for the following:
There are multiple situations where we will send a request to the provider:
In any of the above scenarios, a webhook will be sent as a POST
request, in the following format:
{ "object": "link", "entry": [ { "time": int, "changes": [ { "field": "preview", "value": { "community": { "id": string, }, "user": { "id": string, }, "link": string, } } ] } ] }
This payload contains the following fields:
Field Name | Description |
---|---|
| The webhook topic. This is always |
| A list of requests, is always exactly one. |
| The time when the request was sent. |
| A list of changes in this request, is always exactly one. |
| The webhook field, is always |
| The actual object containing the context of the request. |
| The community of the user that triggered the request. |
| The user that triggered the request. |
| The link that Workplace is attempting to render, which matches the domain and regex configured by the app. |
POST /callback HTTP/1.1 Host: third-party.com Accept: application/json Content-Type: application/json User-Agent: Webhooks/1.0 (https://fb.me/webhooks) X-Hub-Signature: sha1=bf3102e52efd0fd4bd26277030aa180d7b5cf587 ... { "object": "link", "entry": [{ "time": 1501515097793, "changes": [{ "field": "preview", "value": { "community": { "id": "138169208138649" }, "user": { "id": "88575656148087" } "link": "https://company.third-party.com/document-about-this" } }] }] }
When you receive a webhook request, you will need to provide a metadata payload in a specific response format:
{ "data": [ { "link": string, ?"canonical_link": string, ?"title": string, ?"description": string, ?"icon": string, ?"download_url": string, "privacy": 'organization' | 'accessible' | 'inaccessible', ?"type": 'document' | 'folder' | 'task' | 'link', ?"additional_data": [ { "title" => string, "format" => 'text' | 'date' | 'datetime' | 'user', "value" => string | number, ?"color" => 'blue' | 'green' | 'yellow' | orange' | 'red', }, ], } ], ?"linked_user": boolean }
This payload will be expected to contain the following fields:
Field Name | Description |
---|---|
| A collection of items available to the user, this can be empty if the app chooses to not unfurl this link for this user at all. |
| A boolean field indicating whether the third party is aware of the user - if this is set to |
| A unique identifying link for this item, must match the link in the request. |
| A canonical url representation of this content. If different from the link this content will be associated with the canonical content for easier querying of the related shares. |
| The title of this item, must be present except for items that have the privacy set to inaccessible. |
| A short description of the item that will be rendered in the rich preview. |
| A asset for this content for places where Workplace shows a icon of the content. This must be a url and publicly accessible. For best results the asset should be a 16px square. |
| A URL from which Workplace can download a PDF representation of the item to convert it into a image post. This will be ignored for anything except |
| Denotes the object's privacy. This can either be |
| This can either be |
| A collection of metadata that will be rendered in the rich preview. Will be ignored for |
HTTP/1.1 200 OK Content-Type: application/json X-Hub-Signature: sha1=b5a6f32f084100ae5b355174b9bb8398f5fbe983 ... { "data": [ { "link": "https://taaskly.herokuapp.com/task/4", "title": "Launch Workplace Integration for F8", "privacy": "organization", "type": "task", "additional_data": [ { "title": "Owner", "format": "user", "value": "319922278498384" }, { "title": "Created", "format": "datetime", "value": "2018-02-28T03:35:40.827Z" }, { "title": "Priority", "format": "text", "value": "high", "color": "red" } ] } ], "linked_user": true }
The privacy mode determines the visibility, whether we require user auth for the current and subsequent users.
organization
: Visible To User, No user Auth requiredaccessible
: Visible to current user, but user identity mapping may be required for others.inaccessible
: Not visible to userTo add more information on a link preview, you can send up to **three** items of additional data. An additional data item is comprised of a set of key -alue elements. But the value can be formatted in different ways.
Currently four different formats are supported:
text
: Will render the value as is, the value must be a string. For this format additional data can also contain a property color
which must be one of the values blue
, green
, yellow
, orange
or red
. If present, this will render the value with the color as a background.date
: Will parse the value as ISO-8601 date format without time and render it without time indication.datetime
: Will parse the value as ISO-8601 date format with time and timezone and render with with time indication in the users timezone.user
: Will parse the value as a user id and render the user's name.If the privacy mode for your document is marked as either organization
or accessible
, and a download URL is provided, we will send an additional request to download the data.
GET /download/super-fancy-document HTTP/1.1 Host: provider.com Accept: <some mime types> User-Agent: Webhooks/1.0 (https://fb.me/webhooks) X-Hub-Signature: sha1=bf3102e52efd0fd4bd26277030aa180d7b5cf587
Workplace will then take this file and convert it to photos to make a multi-photo post out of it.
As seen above, providing authenticated previews requires some kind of identity mapping. Identity mapping controls whether a Workplace user has the permission to see the content being previewed, and ensures that the access rules of your content are respected on Workplace.
The simplest form of identity mapping is organization-wide mapping, where membership of a Workplace community is sufficient to allow previews to be shown to users on Workplace. This scenario is common when previewing links to a company-wide intranet, or any service where all objects (or at least their metadata) are visible to the entire company.
When your integration is installed on a Workplace community, the community ID can be checked via the /community
endpoint, using the access token you retrieved upon install. You can store this community ID along with the token, and map it to a tenant or organization identifier inside your service. This creates a mapping between a Workplace community and the organization in your service.
Then, when responding to authenticated preview webhook requests, you can check that the webhook payload's community ID matches that organization-linked community ID, then decide whether it's safe to return a metadata payload. Marking that payload's privacy as ORGANIZATION ensures that we won't need to send additional webhooks for each user in that Workplace community.
If more permission granularity is needed, you can support a per-user mapping, ensuring that you can choose whether to render metadata to each viewer on Workplace individually.Workplace sends over a user ID in each webhook payload for authenticated previews. To support per-user mapping, you'll need to know which user record in your system maps to the Workplace user ID sent in the webhook payload.
If this is your first encounter for a given Workplace user ID, you can respond with the boolean field linked_user
set to false
. This will instruct Workplace to show an Enable Preview button, prompting the user to link their account.
When the button is pressed, Workplace will open a dialog to an account linking endpoint that you define, where you can validate the user session in your service. Workplace will open this URL via a POST request, and will pass a signed request parameter, which contains the current user ID and community ID.
POST https://www.example.com/account_linking?redirect_uri=https%3A%2F%2Ffoxfabrics.facebook.com%2Flink_complete HTTP/1.1 Host: foxfabrics.third-party.com Origin: http://www.facebook.com Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 Gecko/20100101 Firefox/57.0 ... signed_request=238fsdfsd.oijdoifjsidf899
In the payload is a parameter signed_request which contains information about this user. This request can be decoded as follows:
The payload contains the following fields:
{ "algorithm": "HMAC-SHA256", "user_id": "88575656148087", "community_id": "138169208138649" }
At this point, you'll have a Workplace user ID and community ID, along with a validated user session in your service, and will be able to record the Workplace ID for this user beside their ID in your service. Upon completion, you should redirect to the url provided on the original request as query param redirect_uri.
GET {$redirect_uri} HTTP/1.1 Host: foxfabrics.facebook.com User-Agent: Mozilla/5.0 Gecko/20100101 Firefox/57.0 Referer: https://www.example.com/account_linking ...
Workplace will then recognize that the identity mapping is complete, and will attempt to request authenticated preview metadata again. This time, you'll be able to respond with linked_user
set to true
, and provide the metadata required.
This entire round-trip should only happen once each time an unrecognised user tries to preview a piece of content for the first time. Once the identity mapping is completed, subsequent previews should be able to bypass this round-trip.
Providing authenticated previews for links people share into Workplace is incredibly powerful by itself. But you can make it even easier for people to share content they're working on in your app, directly from Workplace, by supporting Composer Extensions.
If your integration supports Composer Extensions, you can provide a list of recent or relevant documents when a user starts to write a post in an enabled Workplace group, and Workplace will render that list so that the user can share without having to copy-paste the URL. The resulting share object will behave just like an object that was shared manually, including respecting the permissions of the authenticated preview functionality.
Composer extensions require an identity-mapped user, so that you can return a personalised list of documents to the composer.
To support composer extensions, your app will need the following configuration:
link
and the field collection
.When a linked user invokes your integration's composer extension, Workplace will send a webhook out to fetch a list of documents, in the following format:
{ "object": "link", "entry": [ { "time": int, "changes": [ { "field": "collection", "value": { "community": { "id": string, }, "user": { "id": string, }, ?"link": string, } } ] } ] }
This payload contains the following fields:
Field Name | Description |
---|---|
| The webhook topic. This is always |
| A list of requests, is always exactly one. |
| The time when the request was sent. |
| A list of changes in this request, is always exactly one. |
| The webhook field, is always |
| The actual object containing the context of the request. |
| The community of the user that triggered the request. |
| The user that triggered the request. |
| if the user is drilling down into folders, this is set for subsequent requests, but not present for root requests |
Example:
POST /callback HTTP/1.1 Host: third-party.com Accept: application/json Content-Type: application/json User-Agent: Webhooks/1.0 (https://fb.me/webhooks) X-Hub-Signature: sha1=bf3102e52efd0fd4bd26277030aa180d7b5cf587 ... { "object": "link", "entry": [{ "time": 1501515097793, "changes": [{ "field": "collection", "value": { "community": { "id": "138169208138649" }, "user": { "id": "88575656148087" } } }] }] }
To handle this request, your callback URLneeds to verify the `X-Hub-Signature` and is then respond with a set of objects to be shown in the composer, in the following format:
{ "data": [ { "link": string, "title": string, ?"description": string, ?"icon": string, ?"download_url": string, "privacy": ORGANIZATION | ACCESSIBLE, "type": DOCUMENT | FOLDER | TASK | LINK, ?"additional_data": [ { "title" => string, "format" => 'text' | 'date' | 'datetime' | 'user', "value" => string | number, }, ], } ], ?"linked_user": boolean }
This payload will be expected to contain the following fields:
Field Name | Description |
---|---|
| A collection of items available to the user |
| A boolean field indicating whether the third party is aware of the user - if this is set to |
| A unique identifying link for this item. |
| The title of this item, must be present except for items that have the privacy set to inaccessible. |
| A short description of the item that will be rendered in the rich preview. |
| A asset for this content for places where Workplace shows a icon of the content. This must be a url and publicly accessible. For best results the asset should be a 16px square. |
| A URL from which Workplace can download a PDF representation of the item to convert it into a image post. This will be ignored for anything except |
| Denotes the object's privacy. This can either be |
| This can either be |
| A collection of metadata that will be rendered in the rich preview. Will be ignored for |
Example:
HTTP/1.1 200 OK Content-Type: application/json X-Hub-Signature: sha1=b5a6f32f084100ae5b355174b9bb8398f5fbe983 ... { "data": [ { "link": "https://company.third-party.com/document-A", "title": "Slides for Project A", "description": "Short summary of the slides.", "download_url": "https://company.provider.com/download/document-A", "privacy": "accessible", "type": "document" }, { "link": "https://company.third-party.com/folder-B", "title": "Folder B", "privacy": "public", "type": "folder", } ], "linked_user": true }