├── .gitignore
├── composer.json
├── README.md
└── src
└── Chatway.php
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.lock
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chatway-live-chat/chatway-live-chat-php",
3 | "description": "Embed Chatway chat widget in any PHP app",
4 | "license": "MIT",
5 | "autoload": {
6 | "psr-4": {
7 | "Chatway\\": "src/"
8 | }
9 | },
10 | "authors": [
11 | {
12 | "name": "Chatway Live Chat",
13 | "email": "contact@poptin.com"
14 | }
15 | ],
16 | "minimum-stability": "stable",
17 | "require": {}
18 | }
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Chatway PHP SDK
3 |
4 | The **Chatway live chat PHP SDK** is a lightweight, framework-agnostic PHP library that allows you to easily embed the [Chatway](https://chatway.app/?utm_source=packagist) live chat customer support widget on your website and securely identify your visitors using a simple, chainable API.
5 |
6 | Chatway is a powerful live chat solution for websites, offering features such as live chat customer support, real-time visitor tracking, customizable widgets, canned responses, FAQs, multilingual support, private notes, visitor segmentation, analytics, and more. Chatway is available as a web app, as well as native iOS and Android apps.
7 |
8 | This SDK works with any PHP application, including Laravel, WordPress, custom frameworks, or plain PHP projects.
9 |
10 | 
11 |
12 | ---
13 |
14 | ## Key Features
15 |
16 | - Easily embed the Chatway live chat widget using your project’s widget ID
17 | - Securely verify visitors by ID or email (optional)
18 | - Assign tags with custom colors
19 | - Attach custom fields to visitor sessions
20 | - Clean, chainable syntax
21 | - Fully HTML-escaped output for security
22 |
23 | ---
24 |
25 | ## Installation
26 |
27 | To install the SDK via Composer:
28 |
29 | ```bash
30 | composer require chatway-live-chat/chatway-live-chat-php
31 | ```
32 |
33 | ---
34 |
35 | ## Basic Usage
36 |
37 | Embed the Chatway live chat widget without visitor verification:
38 |
39 | ```php
40 | echo Chatway\Chatway::make('your-widget-id')->getScript();
41 | ```
42 |
43 | You can find your widget ID on the [Chatway Installation Page](https://go.chatway.app/installation) (`id=WIDGET_ID`).
44 |
45 | ---
46 |
47 | ## Visitor Verification (Optional)
48 |
49 | To securely verify logged-in visitors, provide:
50 |
51 | - The **user ID**
52 | - The **email address**
53 | - A **secret key** from the [Visitor Verification page](https://go.chatway.app/visitors-verification)
54 | - Whether to generate the signature based on `'id'` or `'email'`
55 |
56 | All four parameters are required for visitor verification.
57 |
58 | Example:
59 |
60 | ```php
61 | echo Chatway\Chatway::make('your-widget-id', 'your-secret-key', 'id')
62 | ->withVisitor('123', 'user@example.com')
63 | ->getScript();
64 | ```
65 |
66 | This will generate a secure `window.chatwaySettings` block containing a signature and load the chat widget.
67 |
68 | ---
69 |
70 | ## Adding Tags
71 |
72 | You can assign tags to visitors, each with a name and color.
73 |
74 | **Single Tag:**
75 |
76 | ```php
77 | ->setTags('VIP', '#FFD700')
78 | ```
79 |
80 | **Multiple Tags:**
81 |
82 | ```php
83 | ->setTags([
84 | 'VIP' => '#FFD700',
85 | 'Supporter' => '#00FF00'
86 | ]);
87 | ```
88 |
89 | ---
90 |
91 | ## Custom Fields
92 |
93 | You can attach custom fields to enrich visitor session data.
94 |
95 | **Single Field:**
96 |
97 | ```php
98 | ->setCustomFields('Plan', 'Premium')
99 | ```
100 |
101 | **Multiple Fields:**
102 |
103 | ```php
104 | ->setCustomFields([
105 | 'Subscription' => 'Gold',
106 | 'Status' => 'Active'
107 | ]);
108 | ```
109 |
110 | ---
111 |
112 | ## Full Example
113 |
114 | ```php
115 | echo Chatway\Chatway::make('your-widget-id', 'your-secret-key', 'email')
116 | ->withVisitor('123', 'user@example.com')
117 | ->setTags('VIP', '#FFD700')
118 | ->setTags(['Supporter' => '#00FF00'])
119 | ->setCustomFields('Plan', 'Pro')
120 | ->setCustomFields([
121 | 'Country' => 'USA',
122 | 'Language' => 'English'
123 | ])
124 | ->getScript();
125 | ```
126 |
127 | ---
128 |
129 | ## Important Notes
130 |
131 | - For visitor verification, you **must** provide:
132 | - `make(widgetId, secretKey, basedOn)`
133 | - `withVisitor(userId, email)`
134 | - The `basedOn` parameter must be either `'id'` or `'email'`
135 | - All tag names, tag colors, field names, and field values must be strings
136 | - Tags must be an associative array in the format `name => color`
137 | - Custom fields must be an associative array in the format `name => value`
138 |
139 | Invalid input will result in an `InvalidArgumentException`.
140 |
141 | ---
142 |
143 | ## License For This Package
144 |
145 | MIT License © [Chatway](https://chatway.app)
146 |
--------------------------------------------------------------------------------
/src/Chatway.php:
--------------------------------------------------------------------------------
1 | 'id',
32 | 'email' => 'email',
33 | ];
34 |
35 | /**
36 | * @param string $userIdentifier
37 | * @param string|null $hmacSecret
38 | * @param string $hmacBasedOn
39 | * @return self
40 | */
41 | public static function make($userIdentifier, $hmacSecret = null, $hmacBasedOn = self::HMAC_BASE_ON_OPTIONS['id'])
42 | {
43 | $instance = new self();
44 | $instance->userIdentifier = is_string($userIdentifier) ? $userIdentifier : null;
45 | $instance->hmacSecret = is_string($hmacSecret) ? $hmacSecret : null;
46 | $instance->hmacBasedOn = is_string($hmacBasedOn) && in_array($hmacBasedOn, array_values(self::HMAC_BASE_ON_OPTIONS), true) ? $hmacBasedOn : self::HMAC_BASE_ON_OPTIONS['id'];
47 |
48 | return $instance;
49 | }
50 |
51 | /**
52 | * @param string|array $key
53 | * @param string|null $color
54 | * @return self
55 | */
56 | public function setTags($key, $color = null)
57 | {
58 | if (is_array($key)) {
59 | if (!$this->isAssoc($key)) {
60 | throw new InvalidArgumentException('Tags must be an associative array: name => color.');
61 | }
62 |
63 | foreach ($key as $name => $value) {
64 | if (!is_string($name) || !is_string($value)) {
65 | throw new InvalidArgumentException('Both tag name and color must be strings.');
66 | }
67 |
68 | $this->tags[] = ['name' => $name, 'color' => $value];
69 | }
70 | } else {
71 | if (!is_string($key) || !is_string($color)) {
72 | throw new InvalidArgumentException('Tag name and color must be strings.');
73 | }
74 |
75 | $this->tags[] = ['name' => $key, 'color' => $color];
76 | }
77 |
78 | return $this;
79 | }
80 |
81 | /**
82 | * @param string|array $key
83 | * @param string|null $value
84 | * @return self
85 | */
86 | public function setCustomFields($key, $value = null)
87 | {
88 | if (is_array($key)) {
89 | if (!$this->isAssoc($key)) {
90 | throw new InvalidArgumentException('Custom fields must be an associative array: name => value.');
91 | }
92 |
93 | foreach ($key as $name => $val) {
94 | if (!is_string($name) || !is_string($val)) {
95 | throw new InvalidArgumentException('Both custom field name and value must be strings.');
96 | }
97 |
98 | $this->customFields[] = ['name' => $name, 'value' => $val];
99 | }
100 | } else {
101 | if (!is_string($key) || !is_string($value)) {
102 | throw new InvalidArgumentException('Custom field name and value must be strings.');
103 | }
104 |
105 | $this->customFields[] = ['name' => $key, 'value' => $value];
106 | }
107 |
108 | return $this;
109 | }
110 |
111 | /**
112 | * @param string $userId
113 | * @param string $email
114 | * @return self
115 | */
116 | public function withVisitor($userId, $email)
117 | {
118 | $this->userId = is_string($userId) || is_int($userId) || is_float($userId) ? $userId : null;
119 | $this->email = is_string($email) ? $email : null;
120 |
121 | return $this;
122 | }
123 |
124 | /**
125 | * @param array $array
126 | * @return bool
127 | */
128 | protected function isAssoc(array $array)
129 | {
130 | return array_keys($array) !== range(0, count($array) - 1);
131 | }
132 |
133 | /**
134 | * @return string
135 | */
136 | public function getScript()
137 | {
138 | $script = '';
139 |
140 | $shouldVerify = $this->hmacSecret &&
141 | $this->userId !== null &&
142 | $this->email !== null &&
143 | in_array($this->hmacBasedOn, array_values(self::HMAC_BASE_ON_OPTIONS), true);
144 |
145 | if ($shouldVerify) {
146 | $safeId = htmlspecialchars($this->userId, ENT_QUOTES, 'UTF-8');
147 | $safeEmail = htmlspecialchars($this->email, ENT_QUOTES, 'UTF-8');
148 | $hmacBase = $this->hmacBasedOn === 'email' ? $this->email : $this->userId;
149 | $hmac = hash_hmac('sha256', $hmacBase, $this->hmacSecret);
150 |
151 | $tagsJson = json_encode($this->tags);
152 | $customFieldsJson = json_encode($this->customFields);
153 |
154 | $script .= <<
168 | SCRIPT;
169 | }
170 |
171 | $userIdentifier = htmlspecialchars($this->userIdentifier, ENT_QUOTES, 'UTF-8');
172 | $script .= <<
174 | SCRIPT;
175 |
176 | return $script;
177 | }
178 | }
179 |
--------------------------------------------------------------------------------