Skip to content

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 ​

  1. Pertama, verifikasi domain Anda, seperti di Pasang chat. Situs yang belum diverifikasi tidak bisa mengaktifkannya.

  2. Buka Situs → situs Anda → Pemasangan dan, di kartu Pakai di aplikasi Anda, klik Aktifkan chat aplikasi.

  3. Salin tautan halaman chat:

    text
    https://chat.sealreply.com/sk_…

    sk_… adalah kunci situs Anda, sama dengan data-site-key di 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.

swift
import SafariServices

let url = URL(string: "https://chat.sealreply.com/sk_…")!
present(SFSafariViewController(url: url), animated: true)
kotlin
// 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_…"))
dart
// 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,
);
jsx
// 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 = true dan settings.domStorageEnabled = true. Tanpa keduanya, chat tidak terbuka, dan pengguna selalu dianggap pengunjung baru.
  • Gambar dan berkas: WebView Android memerlukan WebChromeClient.onShowFileChooser, jika tidak tombol "+" tidak melakukan apa-apa. iOS dan react-native-webview tidak memerlukan apa-apa.
  • Pesan suara: aplikasi Anda memerlukan izin mikrofon (NSMicrophoneUsageDescription di Info.plist pada iOS; RECORD_AUDIO di Android, diberikan di WebChromeClient.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.

  1. Aktifkan di Situs → situs Anda → Verifikasi identitas pengunjung dan simpan rahasianya di server Anda.

  2. Aplikasi Anda meminta identity_hash pengguna saat ini dari server Anda: HMAC-SHA256 dari ID pengguna dengan rahasia tersebut, persis seperti untuk situs web Anda (caranya).

  3. Tambahkan parameter berikut setelah # pada tautan chat:

    text
    https://chat.sealreply.com/sk_…#external_id=42&identity_hash=<signature>&name=Ann%20Lee&email=ann%40example.com

    Setiap nilai harus di-encode sebagai URL. Kode di bawah ini melakukannya untuk Anda:

swift
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)
kotlin
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"))
dart
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,
);
jsx
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.

swift
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_…")!))
kotlin
// 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_…")
jsx
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 #:

ParameterArti
page_titleNama layar, misalnya Order #1024 atau Product: Blue jacket. Tanpa parameter ini, agen melihat App.
page_urlHalaman yang sama di situs web Anda (diawali http:// atau https://), yang bisa dibuka agen. Kosongkan jika tidak ada.
text
https://chat.sealreply.com/sk_…#page_title=Order%20%231024&page_url=https%3A%2F%2Fshop.example.com%2Forders%2F1024

Semua parameter ​

Semuanya diletakkan setelah # pada tautan, digabung dengan &, dan setiap nilai di-encode sebagai URL. Semuanya opsional.

ParameterArti
external_idID pengguna di sistem Anda, maksimal 128 karakter
identity_hashTanda tangan ID pengguna; hanya berlaku bersama external_id
name, emailDitampilkan kepada agen; tidak pernah menggantikan data yang sudah ada di profil pengunjung
attributes, attributes_hashDetail anggota: attributes adalah objek JSON (misalnya {"plan":"gold"}), ditandatangani seperti di Mengirim detail anggota
page_title, page_urlDari 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 email tidak diminta lagi.
  • Notifikasi push milik Anda sendiri: berlangganan webhook message.created. Untuk pesan dari agen (sender.type bernilai agent), panggil GET /v1/visitors/{visitor_id} dengan conversation.visitor_id dari event tersebut (kunci API memerlukan visitors:read) untuk mendapatkan external_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 lihatYang 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 baruWebView tidak punya local storage (domStorageEnabled di Android), atau selalu dalam mode privat.
Pengguna yang sudah masuk tidak tampil sebagai terverifikasiTanda 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 fotoWebView 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.