Tambahkan chat ke aplikasi Anda
Selain di situs web, Anda juga bisa berbicara dengan pelanggan di aplikasi Anda sendiri. Tambahkan tombol "Hubungi kami" yang membuka chat satu halaman penuh yang di-hosting oleh SealReply. Tidak ada SDK yang perlu dipasang, dan cara ini berfungsi di iOS, Android, Flutter, dan React Native. Pesan, terjemahan, formulir pra-chat, jam operasional, tampilan, dan semua pengaturan lainnya bekerja sama seperti di widget situs web Anda, dan agen tetap membalas dari kotak masuk.
1. Aktifkan halaman chat dan salin tautannya
Pertama, verifikasi domain Anda, seperti di Pasang chat. Situs yang belum diverifikasi tidak bisa mengaktifkannya.
Buka Situs → situs Anda → Pemasangan dan, di kartu Pakai di aplikasi Anda, klik Aktifkan chat aplikasi.
Salin tautan halaman chat:
texthttps://chat.sealreply.com/sk_…sk_…adalah kunci situs Anda, sama dengandata-site-keydi kode sematan situs web Anda.
Sakelar ini nonaktif secara bawaan. Selama belum Anda aktifkan, tautan tersebut hanya menampilkan bahwa chat tidak tersedia, sehingga orang yang mengetahui kunci situs Anda tidak bisa memalsukan halaman chat seolah-olah milik Anda.
2. Buka di aplikasi Anda
Browser dalam aplikasi bawaan sistem bekerja paling baik: SFSafariViewController di iOS, Custom Tabs di Android, inAppBrowserView di Flutter. Gambar, berkas, dan pesan suara tidak memerlukan apa-apa lagi, dan pengguna kembali ke aplikasi Anda dengan Done atau Back.
import SafariServices
let url = URL(string: "https://chat.sealreply.com/sk_…")!
present(SFSafariViewController(url: url), animated: true)// build.gradle: implementation("androidx.browser:browser:1.8.0")
import androidx.browser.customtabs.CustomTabsIntent
CustomTabsIntent.Builder().build()
.launchUrl(context, Uri.parse("https://chat.sealreply.com/sk_…"))// pubspec.yaml: url_launcher: ^6.3.0
import 'package:url_launcher/url_launcher.dart';
await launchUrl(
Uri.parse('https://chat.sealreply.com/sk_…'),
mode: LaunchMode.inAppBrowserView,
);// npm install react-native-webview
import { WebView } from "react-native-webview";
<WebView source={{ uri: "https://chat.sealreply.com/sk_…" }} />Halaman chat tidak punya tombol tutup: pengguna keluar dari halaman ini dengan tombol kembali atau tutup milik aplikasi Anda sendiri.
Di dalam WebView
Untuk menampilkan chat di dalam layar aplikasi Anda sendiri (misalnya di sebuah tab), gunakan WebView (WKWebView di iOS, WebView di Android, react-native-webview). Perhatikan hal berikut:
- Aktifkan JavaScript dan local storage. Di Android, atur
settings.javaScriptEnabled = truedansettings.domStorageEnabled = true. Tanpa keduanya, chat tidak terbuka, dan pengguna selalu dianggap pengunjung baru. - Gambar dan berkas:
WebViewAndroid memerlukanWebChromeClient.onShowFileChooser, jika tidak tombol "+" tidak melakukan apa-apa. iOS danreact-native-webviewtidak memerlukan apa-apa. - Pesan suara: aplikasi Anda memerlukan izin mikrofon (
NSMicrophoneUsageDescriptiondiInfo.plistpada iOS;RECORD_AUDIOdi Android, diberikan diWebChromeClient.onPermissionRequest). Atau nonaktifkan pesan suara di Situs → Fitur pengunjung.
Aplikasi yang dibangun dari halaman web cukup membuka tautan halaman chat. Halaman chat tidak bisa dimasukkan ke dalam iframe, sehingga tidak ada situs web lain yang bisa membungkus chat Anda di halamannya sendiri.
3. Biarkan agen mengenali pengguna yang sudah masuk
Jika aplikasi Anda punya akun pengguna, Anda bisa mengenali pengguna yang sudah masuk seperti di situs web Anda: mereka tampil sebagai terverifikasi, dikenali sebagai orang yang sama di setiap perangkat, dan bisa melihat chat sebelumnya di menu chat.
Aktifkan di Situs → situs Anda → Verifikasi identitas pengunjung dan simpan rahasianya di server Anda.
Aplikasi Anda meminta
identity_hashpengguna saat ini dari server Anda: HMAC-SHA256 dari ID pengguna dengan rahasia tersebut, persis seperti untuk situs web Anda (caranya).Tambahkan parameter berikut setelah
#pada tautan chat:texthttps://chat.sealreply.com/sk_…#external_id=42&identity_hash=<signature>&name=Ann%20Lee&email=ann%40example.comSetiap nilai harus di-encode sebagai URL. Kode di bawah ini melakukannya untuk Anda:
var parts = URLComponents()
parts.queryItems = [
URLQueryItem(name: "external_id", value: user.id),
URLQueryItem(name: "identity_hash", value: identityHash), // from your server
URLQueryItem(name: "name", value: user.name),
URLQueryItem(name: "email", value: user.email),
]
let url = URL(string: "https://chat.sealreply.com/sk_…#" + (parts.percentEncodedQuery ?? ""))!
present(SFSafariViewController(url: url), animated: true)val fragment = Uri.Builder()
.appendQueryParameter("external_id", user.id)
.appendQueryParameter("identity_hash", identityHash) // from your server
.appendQueryParameter("name", user.name)
.appendQueryParameter("email", user.email)
.build().encodedQuery
CustomTabsIntent.Builder().build()
.launchUrl(context, Uri.parse("https://chat.sealreply.com/sk_…#$fragment"))final fragment = Uri(queryParameters: {
'external_id': user.id,
'identity_hash': identityHash, // from your server
'name': user.name,
'email': user.email,
}).query;
await launchUrl(
Uri.parse('https://chat.sealreply.com/sk_…#$fragment'),
mode: LaunchMode.inAppBrowserView,
);const fragment = Object.entries({
external_id: user.id,
identity_hash: identityHash, // from your server
name: user.name,
email: user.email,
}).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join("&");
<WebView source={{ uri: `https://chat.sealreply.com/sk_…#${fragment}` }} />Saat pengguna keluar atau pengguna lain masuk, buka halaman chat tanpa detail ini (atau dengan detail pengguna baru). Halaman chat kemudian dimulai sebagai pengunjung baru, dan chat pengguna sebelumnya tidak ditampilkan.
Jaga keamanan tanda tangan
identity_hash berfungsi seperti kata sandi chat milik pengguna tersebut: siapa pun yang memilikinya bisa membaca chat mereka. Simpan rahasia di server Anda dan jangan pernah menaruhnya di aplikasi Anda.
Tautan yang sudah ditandatangani tidak pernah kedaluwarsa, dan siapa pun yang memilikinya bisa chat sebagai pengguna tersebut: buat tautan baru setiap kali chat dibuka, dan jangan pernah mencatatnya di log atau membagikannya.
Bagian setelah # tidak pernah dikirim ke server mana pun (termasuk server kami), dan halaman chat menghapusnya dari alamat begitu selesai membacanya (memuat ulang di tab yang sama tetap mengenali pengguna). Namun, dengan Custom Tabs Android, Chrome mungkin menyimpan tautan lengkapnya di riwayat penelusuran ponsel tersebut. Jika hal itu penting bagi Anda, gunakan cara WebView di bawah, yang menjauhkan tanda tangan dari tautan.
Menjauhkan tanda tangan dari tautan (WebView)
Di WebView, atur window.sealreplySettings sebelum halaman dimuat, seperti di situs web, dan jangan sertakan external_id dan identity_hash di tautan. Jika tautan juga memuatnya, yang dipakai adalah nilai di tautan.
let settings = """
window.sealreplySettings = { identity: {
external_id: \(jsonString(user.id)),
identity_hash: \(jsonString(identityHash)),
name: \(jsonString(user.name))
} };
"""
let config = WKWebViewConfiguration()
config.userContentController.addUserScript(
WKUserScript(source: settings, injectionTime: .atDocumentStart, forMainFrameOnly: true)
)
let webView = WKWebView(frame: .zero, configuration: config)
webView.load(URLRequest(url: URL(string: "https://chat.sealreply.com/sk_…")!))// build.gradle: implementation("androidx.webkit:webkit:1.12.0")
import androidx.webkit.WebViewCompat
import androidx.webkit.WebViewFeature
import org.json.JSONObject
val identity = JSONObject()
.put("external_id", user.id)
.put("identity_hash", identityHash)
.put("name", user.name)
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
WebViewCompat.addDocumentStartJavaScript(
webView,
"window.sealreplySettings = { identity: $identity };",
setOf("https://chat.sealreply.com"),
)
}
webView.loadUrl("https://chat.sealreply.com/sk_…")const settings = `window.sealreplySettings = { identity: ${JSON.stringify({
external_id: user.id,
identity_hash: identityHash,
name: user.name,
})} }; true;`;
<WebView
source={{ uri: "https://chat.sealreply.com/sk_…" }}
injectedJavaScriptBeforeContentLoaded={settings}
/>jsonString mewakili proses mengubah string menjadi literal string JSON (diberi tanda kutip dan di-escape), misalnya dengan JSONEncoder. Jangan pernah menempelkan nama pengguna ke dalam kode apa adanya.
4. Beri tahu agen dari mana pengguna datang
Widget di situs web Anda memberi tahu agen halaman yang sedang dibuka pengunjung. Aplikasi tidak punya alamat, jadi tambahkan setelah #:
| Parameter | Arti |
|---|---|
page_title | Nama layar, misalnya Order #1024 atau Product: Blue jacket. Tanpa parameter ini, agen melihat App. |
page_url | Halaman yang sama di situs web Anda (diawali http:// atau https://), yang bisa dibuka agen. Kosongkan jika tidak ada. |
https://chat.sealreply.com/sk_…#page_title=Order%20%231024&page_url=https%3A%2F%2Fshop.example.com%2Forders%2F1024Semua parameter
Semuanya diletakkan setelah # pada tautan, digabung dengan &, dan setiap nilai di-encode sebagai URL. Semuanya opsional.
| Parameter | Arti |
|---|---|
external_id | ID pengguna di sistem Anda, maksimal 128 karakter |
identity_hash | Tanda tangan ID pengguna; hanya berlaku bersama external_id |
name, email | Ditampilkan kepada agen; tidak pernah menggantikan data yang sudah ada di profil pengunjung |
attributes, attributes_hash | Detail anggota: attributes adalah objek JSON (misalnya {"plan":"gold"}), ditandatangani seperti di Mengirim detail anggota |
page_title, page_url | Dari mana pengguna datang, seperti di atas |
Halaman chat mengikuti bahasa ponsel, dan mode gelapnya juga mengikuti sistem (jika tampilan situs Anda diatur untuk mengikuti sistem pengunjung).
Balasan setelah pengguna meninggalkan aplikasi Anda
Halaman chat hanya menerima pesan secara langsung selama halaman tersebut terbuka. Untuk menjangkau pengguna yang sudah pergi sebelum agen membalas:
- Email: saat balasan lambat, halaman chat meminta email pengguna (lihat Saat Anda offline). Pengguna yang sudah masuk dan mengirimkan
emailtidak diminta lagi. - Notifikasi push milik Anda sendiri: berlangganan webhook
message.created. Untuk pesan dari agen (sender.typebernilaiagent), panggilGET /v1/visitors/{visitor_id}denganconversation.visitor_iddari event tersebut (kunci API memerlukanvisitors:read) untuk mendapatkanexternal_id, yaitu ID pengguna Anda, lalu beri tahu mereka lewat push aplikasi Anda sendiri. Saat mereka mengetuknya, buka halaman chat lagi dan balasannya sudah ada di sana.
Pertanyaan umum
| Yang Anda lihat | Yang perlu dilakukan |
|---|---|
| "Chat sedang tidak tersedia" | Pastikan Pakai di aplikasi Anda aktif, domain situs sudah diverifikasi, situs tidak dijeda karena melebihi batas paket, dan sk_… di tautan lengkap. |
| Pengguna selalu dianggap pengunjung baru | WebView tidak punya local storage (domStorageEnabled di Android), atau selalu dalam mode privat. |
| Pengguna yang sudah masuk tidak tampil sebagai terverifikasi | Tanda tangannya salah. Pastikan Anda memakai rahasia milik situs ini, menandatangani string external_id persis apa adanya, dan meng-encode nilai di tautan sebagai URL. |
| "+" tidak membuka pemilih foto | WebView Android memerlukan onShowFileChooser; atau gunakan Custom Tabs. |
Chat dari aplikasi Anda dihitung dalam kuota percakapan bulanan situs, sama seperti chat dari situs web Anda, dan tampil bersama pengunjung situs web Anda di kotak masuk.