Skip to content

Commit d95785b

Browse files
committed
feat: examples showing how to generate Cobrowse links
This PR adds two demos: 1. Sharing a link with the customer to start a Cobrowse session immediately 2. Sharing a link that can be used to start a Cobrowse session later (eg. for scheduling purposes) The demos are built with cobrowse-agent-sdk, cobrowse-agent-ui, React, Vite and Typescript.
1 parent 0446056 commit d95785b

31 files changed

+971
-0
lines changed

share-links/README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Share links demo
2+
3+
It is often useful for an agent to share a link with a customer to start a Cobrowse session.
4+
5+
This demo shows two ways to do that using the Cobrowse Agent SDK.
6+
7+
Use session links when you wish to start a Cobrowse session immediately. The agent shares a link to their current session with the customer. The customer clicks on the link and joins the Cobrowse session immediately. These links automatically expire after 15 minutes.
8+
9+
When the agent wants to schedule a Cobrowse session later, they should share a device link instead. Device links tag the customer so the agent can use the smart connect feature to connect when the customer comes online.
10+
11+
This example uses the Cobrowse Agent SDK, Vite, React and Typescript.
12+
13+
## Running the demo
14+
15+
```sh
16+
npm install
17+
npm run dev
18+
```
19+
20+
## Sharing a link to a session
21+
22+
The agent starts a session and then shares a link with the
23+
customer so they can join the session.
24+
25+
On the customer side, the web page should check for the session id
26+
and use that to get the session:
27+
28+
```js
29+
if (CobrowseIO.currentSession == null) {
30+
const searchParams = new URLSearchParams(window.location.search)
31+
const session = searchParams.get('session_id')
32+
if (session) {
33+
CobrowseIO.getSession(session);
34+
}
35+
}
36+
```
37+
38+
Sessions automatically expire after 15 minutes if the customer
39+
does not join.
40+
41+
## Scheduling a Cobrowse session later
42+
43+
The agent shares a link with the customer that will uniquely
44+
identify the customer. The agent can use the Smart Connect button
45+
to start a session when the customer comes online.
46+
47+
On the customer side, the web page should check for the meeting id
48+
and tag the device so the agent can identify the customer.
49+
50+
```js
51+
if (CobrowseIO.currentSession == null) {
52+
const searchParams = new URLSearchParams(window.location.search)
53+
const meeting_id = searchParams('meeting_id')
54+
if (meeting_id) CobrowseIO.customData['meeting_id'] = meeting_id
55+
}
56+
```
57+
58+
Your Cobrowse.io account must have device registration enabled to work.

share-links/index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/cobrowse.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Share Links | Cobrowse Agent SDK</title>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>

share-links/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "share-links",
3+
"private": true,
4+
"version": "0.1.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "tsc -b && vite build",
9+
"lint": "biome check --write",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@fortawesome/fontawesome-svg-core": "^6.7.2",
14+
"@fortawesome/free-solid-svg-icons": "^6.7.2",
15+
"@fortawesome/react-fontawesome": "^0.2.2",
16+
"cobrowse-agent-sdk": "^2.7.0",
17+
"cobrowse-agent-ui": "^1.2.0",
18+
"nanoid": "^5.1.5",
19+
"react": "^19.1.0",
20+
"react-dom": "^19.1.0"
21+
},
22+
"devDependencies": {
23+
"@biomejs/biome": "2.1.3",
24+
"@types/react": "^19.1.8",
25+
"@types/react-dom": "^19.1.6",
26+
"@vitejs/plugin-react": "^4.6.0",
27+
"globals": "^16.3.0",
28+
"typescript": "~5.8.3",
29+
"vite": "^7.0.4"
30+
}
31+
}

share-links/public/cobrowse.svg

Lines changed: 3 additions & 0 deletions
Loading

share-links/src/App.css

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
main {
2+
display: flex;
3+
flex-direction: column;
4+
flex: 1;
5+
background: #ffffff;
6+
border-width: var(--frame-border-width);
7+
border-color: var(--frame-border-color);
8+
border-style: var(--frame-border-style);
9+
border-radius: var(--frame-border-radius);
10+
padding: 1rem;
11+
}
12+
13+
header {
14+
display: flex;
15+
justify-content: space-between;
16+
align-items: baseline;
17+
}
18+
19+
header > fieldset {
20+
display: flex;
21+
flex: 1;
22+
border: none;
23+
justify-content: end;
24+
}
25+
26+
fieldset > input {
27+
text-align: right;
28+
font-size: 0.75rem;
29+
line-height: 1.75rem;
30+
color: oklch(55.4% 0.046 257.417);
31+
background: none;
32+
border: none;
33+
border-top-right-radius: 0;
34+
border-bottom-right-radius: 0;
35+
}

share-links/src/App.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { nanoid } from "nanoid";
2+
import React from "react";
3+
import CobrowseProvider from "./CobrowseProvider.tsx";
4+
import NavBar from "./components/NavBar.tsx";
5+
import DeviceLinkDemo from "./DeviceLinkDemo.tsx";
6+
import SessionLinkDemo from "./SessionLinkDemo.tsx";
7+
import type { Tab } from "./types.ts";
8+
import { getSearchParam, setSearchParam } from "./util/searchParams.ts";
9+
import "./App.css";
10+
11+
const DEMO_ID =
12+
getSearchParam("demo_id") || setSearchParam("demo_id", nanoid());
13+
const DEFAULT_URL = "https://docs.cobrowse.io";
14+
const DEFAULT_TOKEN = getSearchParam("token") || "";
15+
const DEFAULT_API = getSearchParam("api") || "";
16+
//const DEFAULT_URL = "https://cobrowse-sdk-js-examples.cbrws.io/web-example/demo"
17+
18+
function App({
19+
demoId = DEMO_ID,
20+
token = DEFAULT_TOKEN,
21+
api = DEFAULT_API,
22+
} = {}) {
23+
const [activeTab, setActiveTab] = React.useState<Tab>("");
24+
const [meetingUrl, setMeetingUrl] = React.useState<string>(() => {
25+
return getSearchParam("meeting_url") || DEFAULT_URL;
26+
});
27+
const [meetingId, setMeetingId] = React.useState<string>(nanoid);
28+
29+
function handleClick(tab: Tab) {
30+
setMeetingId(nanoid());
31+
setActiveTab(tab);
32+
}
33+
34+
return (
35+
<CobrowseProvider demoId={demoId} token={token} api={api}>
36+
<NavBar
37+
meetingUrl={meetingUrl}
38+
setMeetingUrl={setMeetingUrl}
39+
setTab={handleClick}
40+
/>
41+
<main>
42+
{activeTab === "session" && (
43+
<SessionLinkDemo
44+
demoId={demoId}
45+
meetingUrl={meetingUrl}
46+
meetingId={meetingId}
47+
/>
48+
)}
49+
{activeTab === "device" && (
50+
<DeviceLinkDemo
51+
demoId={demoId}
52+
meetingUrl={meetingUrl}
53+
meetingId={meetingId}
54+
/>
55+
)}
56+
</main>
57+
</CobrowseProvider>
58+
);
59+
}
60+
61+
export default App;

share-links/src/CobrowseContext.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type CobrowseAPI from "cobrowse-agent-sdk";
2+
import { createContext, useContext } from "react";
3+
4+
export const CobrowseContext = createContext<null | CobrowseAPI>(null);
5+
6+
export function useCobrowse(): CobrowseAPI {
7+
const ctx = useContext(CobrowseContext);
8+
if (ctx === null) {
9+
throw new Error("useCobrowse must be used within an CobrowseProvider");
10+
}
11+
return ctx;
12+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import CobrowseAPI from "cobrowse-agent-sdk";
2+
import type { PropsWithChildren } from "react";
3+
import { useEffect, useState } from "react";
4+
import { CobrowseContext } from "./CobrowseContext.ts";
5+
6+
async function fetchToken(demoId: string): Promise<string> {
7+
// !! WARNING READ THIS !!
8+
// You should NOT use this endpoint to get your own token. This endpoint is
9+
// specific to the cobrowse.io hosted online demo. It will not work with your
10+
// account and devices.
11+
// You should fetch a token in an authenticated way from your own server for
12+
// the user. See our documentation on generating a JWT for cobrowse:
13+
// https://docs.cobrowse.io/agent-side-integrations/custom-iframe-integrations/json-web-tokens-jwts
14+
const res = await fetch(
15+
`https://cobrowse.io/api/1/demo/token?demo_id=${demoId}`,
16+
);
17+
const { token } = await res.json();
18+
return token;
19+
}
20+
21+
type WithCobrowseProps = {
22+
demoId: string;
23+
token?: string;
24+
api?: string;
25+
};
26+
27+
export default function CobrowseProvider({
28+
demoId,
29+
token,
30+
api,
31+
children,
32+
}: PropsWithChildren<WithCobrowseProps>) {
33+
const options: Record<string, any> = {}
34+
if (api) options['api'] = api
35+
const [cobrowse] = useState<CobrowseAPI>(() => new CobrowseAPI("", options));
36+
37+
useEffect(() => {
38+
console.log(`CobrowseAPI: api=${api} token=${token} demoId=${demoId}`);
39+
async function setupClient() {
40+
cobrowse.token = token || (await fetchToken(demoId));
41+
}
42+
setupClient();
43+
}, [cobrowse, demoId, token]);
44+
45+
return <CobrowseContext value={cobrowse}>{children}</CobrowseContext>;
46+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.deviceList {
2+
list-style-type: none;
3+
flex: 1;
4+
}

0 commit comments

Comments
 (0)