{"id":25385204,"url":"https://github.com/userlike/messenger","last_synced_at":"2025-07-18T19:04:09.958Z","repository":{"id":38308662,"uuid":"273023425","full_name":"userlike/messenger","owner":"userlike","description":"Userlike Messenger API","archived":false,"fork":false,"pushed_at":"2025-07-01T08:34:16.000Z","size":3897,"stargazers_count":10,"open_issues_count":1,"forks_count":2,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-07-01T08:38:33.719Z","etag":null,"topics":["api","messenger","userlike"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/userlike.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-06-17T16:21:07.000Z","updated_at":"2025-07-01T08:34:20.000Z","dependencies_parsed_at":"2024-05-06T15:46:53.267Z","dependency_job_id":"45455464-9fa7-4777-ab9b-9d649d53a952","html_url":"https://github.com/userlike/messenger","commit_stats":null,"previous_names":[],"tags_count":107,"template":false,"template_full_name":null,"purl":"pkg:github/userlike/messenger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userlike%2Fmessenger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userlike%2Fmessenger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userlike%2Fmessenger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userlike%2Fmessenger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/userlike","download_url":"https://codeload.github.com/userlike/messenger/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/userlike%2Fmessenger/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265815260,"owners_count":23832877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","messenger","userlike"],"created_at":"2025-02-15T09:40:21.884Z","updated_at":"2025-07-18T19:04:09.945Z","avatar_url":"https://github.com/userlike.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg width=\"144\" height=\"144\" src=\"https://avatars2.githubusercontent.com/u/1116280\"\u003e\n\u003c/p\u003e\n\n\n# Userlike Messenger API\n\n\u003c!-- prettier-ignore-start --\u003e\n\n## Table of Contents\n\n* [Install](#install)\n  + [ES modules](#es-modules)\n  + [commonjs](#commonjs)\n  + [AMD loader (requirejs)](#amd-loader-requirejs)\n  + [script tag](#script-tag)\n* [Upgrading to Version 2](#upgrading-to-version-2)\n* [Usage](#usage)\n* [Examples](#examples)\n  + [Create the API](#create-the-api)\n  + [Create/destroy messenger](#createdestroy-messenger)\n  + [Change visibility](#change-visibility)\n  + [Clear user session / Logout](#clear-user-session--logout)\n  + [Maximize/Minimize](#maximizeminimize)\n  + [Set custom data](#set-custom-data)\n  + [Set contact info](#set-contact-info)\n  + [Listen to changes](#listen-to-changes)\n  + [Observables](#observables)\n* [Error Handling](#error-handling)\n* [Contact Authentication](#contact-authentication)\n* [CSP](#csp)\n* [Versioning](#versioning)\n  + [Dates](#dates)\n\n\u003c!-- prettier-ignore-end --\u003e\n\n## Install\n\n```\nnpm install @userlike/messenger\n```\n\n### ES modules\n\n```js\nimport { createMessenger } from \"@userlike/messenger\";\n```\n\n### commonjs\n\n```js\nconst { createMessenger } = require(\"@userlike/messenger\");\n```\n\n### AMD loader (requirejs)\n\n```js\nrequire(['userlike-messenger'], function (userlike) {\n  userlike.createMessenger({ ... });\n});\n```\n\n### script tag\n\n```html\n\u003c!--\nunpkg is an open source project. It's not affiliated with Userlike. Use it to quickly and easily load\nmessenger API without bundling it yourself. We highly advise against using unpkg for production.\n--\u003e\n\u003cscript src=\"https://unpkg.com/@userlike/messenger/dist/browser/index.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  UserlikeMessenger.createMessenger({ ... });\n\u003c/script\u003e\n```\n\n## Upgrading to Version 2\n\nVersion 2 introduces breaking changes, including support for widget routers on single page applications and improved API structure. If you are using version 1, we highly recommend upgrading to version 2 as soon as possible.\n\n- **Key changes in v2:**\n  - Support for widget routers in single page applications (SPA)\n  - Improved API structure and error handling\n\nSee the [migration guide](./MIGRATION.md) for detailed upgrade instructions.\n\n## Usage\n\nSee [examples](#examples) for further details on how to use `createMessenger`.\n\n**Typescript:** [typescript playground](https://codesandbox.io/p/sandbox/userlike-messenger-api-vanilla-v2-kjkflq).\n\n**Javascript:** [javascript playground](https://codesandbox.io/p/sandbox/bold-ramanujan-9tcmmk).\n\n**React + typescript:** [react playground](https://codesandbox.io/p/sandbox/userlike-messenger-api-v2-p2c8fq).\n\n## Examples\n\n### Create the API\n\n```typescript\nimport { createMessenger, v1 } from \"@userlike/messenger\";\n\nasync function createApi(): Promise\u003cv2.Api\u003e {\n  const result = await createMessenger({\n    version: 2,\n    widgetKey: \"YOUR_WIDGET_SECRET\",\n  });\n\n  if (result.kind === \"error\") throw new Error(result.error);\n\n  const { api } = result.value;\n\n  if (api === null) {\n    throw new Error(\n      \"api reached end-of-life, please check documentation and upgrade.\",\n    );\n  }\n\n  return api;\n}\n```\n\n### Create/destroy messenger\n\n```typescript\n(api: v2.Api) =\u003e {\n  const subscription = api.mount().subscribe((result) =\u003e {\n    if (result.kind === \"error\") {\n      console.error(result.error);\n      return;\n    }\n\n    if (result.value === null) {\n      console.log(\"messenger is not mounted\", result.reason);\n      return;\n    }\n\n    const messenger = result.value;\n  });\n\n  // Unsubscribing would destroy the messenger\n  subscription.unsubscribe();\n};\n```\n\n### Change visibility\n\n```typescript\n// Hide button and notifications\nasync (messenger: v2.Messenger) =\u003e {\n  await messenger.setVisibility({\n    main: true,\n    button: false,\n    notifications: false,\n  });\n};\n\n// Show everything\nasync (messenger: v2.Messenger) =\u003e {\n  await messenger.setVisibility({\n    main: true,\n    button: true,\n    notifications: true,\n  });\n};\n```\n\n### Clear user session / Logout\n\n```typescript\nasync (messenger: v2.Messenger) =\u003e {\n  await messenger.logout();\n};\n```\n\n### Maximize/Minimize\n\n```typescript\nasync (messenger: v2.Messenger) =\u003e {\n  await messenger.maximize();\n  await messenger.minimize();\n};\n```\n\n### Set custom data\n\n```typescript\nasync (messenger: v2.Messenger) =\u003e {\n  await messenger.setCustomData({\n    test: \"test data\",\n  });\n};\n```\n\n### Set contact info\n\n```typescript\nasync (messenger: v2.Messenger) =\u003e {\n  await messenger.setContactInfo({\n    name: \"Foo Bar\",\n    email: \"foobar@example.com\",\n  });\n};\n```\n\n### Listen to changes\n\n```typescript\n(messenger: v2.Messenger) =\u003e {\n  const subscription = messenger.state$.subscribe({\n    next: (state) =\u003e console.log(\"next\", state),\n    complete: () =\u003e console.log(\"complete\"),\n  });\n\n  // unsubscribe when you don't need to listen to changes anymore\n  subscription.unsubscribe();\n};\n```\n\n### Observables\n\nBoth `api.mount()` and `messenger.state` are observables. You can use `rxjs`, or other streaming libraries:\n\n```typescript\nimport * as Rx from \"rxjs\";\nimport * as $ from \"rxjs/operators\";\nimport { v1 } from \"@userlike/messenger\";\n\n(api: v2.Api) =\u003e {\n  const unreadMessageCount$ = Rx.pipe(\n    api.mount(),\n    $.filter((result) =\u003e result.kind === \"success\"),\n    $.map((result) =\u003e result.value),\n    $.switchMap((messenger) =\u003e messenger.state$),\n    $.map(v2.getUnreadMessageCount),\n  );\n};\n```\n\n## Error Handling\n\nAll Messenger API methods return a `Result` object, which is a tagged union of `Success` and `Error` (similar to [Rust's `Result\u003cT, E\u003e`](https://doc.rust-lang.org/std/result/)). The API itself never throws exceptions. You are responsible for checking the result and handling errors as needed.\n\n**Result Structure:**\n\n- `{ kind: \"success\", value: ... }` for successful operations\n- `{ kind: \"error\", error: ... }` for failed operations\n\n**Example:**\n\n```typescript\nconst result = await api.someAction();\n\nif (result.kind === \"error\") {\n  // Handle the error (e.g., log, show message, or throw)\n  console.error(\"Messenger API error:\", result.error);\n  throw new Error(result.error);\n}\n\n// Success case\nconst value = result.value;\n```\n\n\u003e **Best Practice:** Always check the `kind` property before accessing the result value. Using TypeScript helps ensure you handle both success and error cases safely.\n\nFor more details, see the [`Result` type definition](https://github.com/userlike/messenger/blob/master/packages/messenger-internal/src/shared/Result.ts).\n\n## Contact Authentication\n\nTo use Contact Authentication, you first need to create a secret \"Messenger API authentication signing key\" in your API settings. You then need to securely store that signing key in your system and create a service that uses that signing to create a JWT that we use to authenticate a Contact.\n\nThe JWT payload must be signed using your messenger signing key via `HMAC-SHA256` and must have the following shape:\n\n```typescript\ninterface TokenPayload {\n  sub: string; // a unique ID of your choice that you want to use to identify the Contact (max length: 255)\n  iat: number; // \"issued at\" unix timestamp, in seconds\n  exp: number; // \"expires at\" unix timestamp, in seconds\n}\n```\n\nYou can then pass the externalToken configuration when calling the mount() function of our Messenger API:\n\n```typescript\napi.mount({\n  externalToken: {\n    getToken: () =\u003e {\n      // return a JWT created by your service\n    },\n    onError: (e) =\u003e {\n      // callback to handle errors related to contact authentication\n    },\n  },\n});\n```\n\nWhen the JWT is valid, your Contacts will have access to all their ongoing and previous conversations regardless of which browser, device, or platform they're using the Messenger on.\n\nIn case the JWT is invalid (for example when it expired or was signed incorrectly) the `onError` callback is called.\n\n## CSP\n\nTo use the Userlike Messenger API in your application, you need to ensure that your Content Security Policy (CSP) allows the necessary resources. Please follow Userlike's [CSP documentation](https://docs.userlike.com/setup/widget-integration/content-security-policy) to configure your CSP correctly.\n\nA nonce can be provided to the Messenger API as follows:\n\n```typescript\napi.mount({\n  nonce: \"your-nonce\",\n});\n```\n\n## Versioning\n\n_Userlike Messenger API_ follows relatively short cycles of deprecations and end of lifes. The API versioning is designed in such a way to force its consumers to be prepared and to plan for an end-of-life situation. When end-of-life date is reached. that version of the API becomes unavailable; which is reflected in Typescript types.\n\nWe highly suggest you to use Typescript to consume _Userlike Messenger API_ so to be able to handle unhappy code paths safely.\n\n### Dates\n\n- **v2** \u003cbr /\u003e\n  Deprecation: 2026-08-01 \u003cbr /\u003e\n  End-of-life: 2027-08-01\n- **v1** \u003cbr /\u003e\n  Deprecation: 2025-08-01 \u003cbr /\u003e\n  End-of-life: 2026-08-01\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuserlike%2Fmessenger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuserlike%2Fmessenger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuserlike%2Fmessenger/lists"}