Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions share-links/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Share links demo

It is often useful for an agent to share a link with a customer to start a Cobrowse session.

This demo shows two ways to do that using the Cobrowse Agent SDK.

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.

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.

This example uses the Cobrowse Agent SDK, Vite, React and Typescript.

## Running the demo

```sh
npm install
npm run dev
```

## Sharing a link to a session

The agent starts a session and then shares a link with the
customer so they can join the session.

On the customer side, the web page should check for the session id
and use that to get the session:

```js
if (CobrowseIO.currentSession == null) {
const searchParams = new URLSearchParams(window.location.search)
const session = searchParams.get('session_id')
if (session) {
CobrowseIO.getSession(session);
}
}
```

Sessions automatically expire after 15 minutes if the customer
does not join.

## Scheduling a Cobrowse session later

The agent shares a link with the customer that will uniquely
identify the customer. The agent can use the Smart Connect button
to start a session when the customer comes online.

On the customer side, the web page should check for the meeting id
and tag the device so the agent can identify the customer.

```js
if (CobrowseIO.currentSession == null) {
const searchParams = new URLSearchParams(window.location.search)
const meeting_id = searchParams('meeting_id')
if (meeting_id) CobrowseIO.customData['meeting_id'] = meeting_id
}
```

Your Cobrowse.io account must have device registration enabled to work.
13 changes: 13 additions & 0 deletions share-links/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/cobrowse.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Share Links | Cobrowse Agent SDK</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
31 changes: 31 additions & 0 deletions share-links/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "share-links",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "biome check --write",
"preview": "vite preview"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.2",
"cobrowse-agent-sdk": "^2.7.0",
"cobrowse-agent-ui": "^1.2.0",
"nanoid": "^5.1.5",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@biomejs/biome": "2.1.3",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.6.0",
"globals": "^16.3.0",
"typescript": "~5.8.3",
"vite": "^7.0.4"
}
}
3 changes: 3 additions & 0 deletions share-links/public/cobrowse.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions share-links/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
main {
display: flex;
flex-direction: column;
flex: 1;
background: #ffffff;
border-width: var(--frame-border-width);
border-color: var(--frame-border-color);
border-style: var(--frame-border-style);
border-radius: var(--frame-border-radius);
padding: 1rem;
}

header {
display: flex;
justify-content: space-between;
align-items: baseline;
}

header > fieldset {
display: flex;
flex: 1;
border: none;
justify-content: end;
}

fieldset > input {
text-align: right;
font-size: 0.75rem;
line-height: 1.75rem;
color: oklch(55.4% 0.046 257.417);
background: none;
border: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
61 changes: 61 additions & 0 deletions share-links/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { nanoid } from "nanoid";
import React from "react";
import CobrowseProvider from "./CobrowseProvider.tsx";
import NavBar from "./components/NavBar.tsx";
import DeviceLinkDemo from "./DeviceLinkDemo.tsx";
import SessionLinkDemo from "./SessionLinkDemo.tsx";
import type { Tab } from "./types.ts";
import { getSearchParam, setSearchParam } from "./util/searchParams.ts";
import "./App.css";

const DEMO_ID =
getSearchParam("demo_id") || setSearchParam("demo_id", nanoid());
const DEFAULT_URL =
"https://cobrowse-sdk-js-examples.cbrws.io/web-example/demo";
const DEFAULT_TOKEN = getSearchParam("token") || "";
const DEFAULT_API = getSearchParam("api") || "";

function App({
demoId = DEMO_ID,
token = DEFAULT_TOKEN,
api = DEFAULT_API,
} = {}) {
const [activeTab, setActiveTab] = React.useState<Tab>("");
const [meetingUrl, setMeetingUrl] = React.useState<string>(() => {
return getSearchParam("meeting_url") || DEFAULT_URL;
});
const [meetingId, setMeetingId] = React.useState<string>(nanoid);

function handleClick(tab: Tab) {
setMeetingId(nanoid());
setActiveTab(tab);
}

return (
<CobrowseProvider demoId={demoId} token={token} api={api}>
<NavBar
meetingUrl={meetingUrl}
setMeetingUrl={setMeetingUrl}
setTab={handleClick}
/>
<main>
{activeTab === "session" && (
<SessionLinkDemo
demoId={demoId}
meetingUrl={meetingUrl}
meetingId={meetingId}
/>
)}
{activeTab === "device" && (
<DeviceLinkDemo
demoId={demoId}
meetingUrl={meetingUrl}
meetingId={meetingId}
/>
)}
</main>
</CobrowseProvider>
);
}

export default App;
12 changes: 12 additions & 0 deletions share-links/src/CobrowseContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type CobrowseAPI from "cobrowse-agent-sdk";
import { createContext, useContext } from "react";

export const CobrowseContext = createContext<null | CobrowseAPI>(null);

export function useCobrowse(): CobrowseAPI {
const ctx = useContext(CobrowseContext);
if (ctx === null) {
throw new Error("useCobrowse must be used within an CobrowseProvider");
}
return ctx;
}
46 changes: 46 additions & 0 deletions share-links/src/CobrowseProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import CobrowseAPI from "cobrowse-agent-sdk";
import type { PropsWithChildren } from "react";
import { useEffect, useState } from "react";
import { CobrowseContext } from "./CobrowseContext.ts";

async function fetchToken(demoId: string): Promise<string> {
// !! WARNING READ THIS !!
// You should NOT use this endpoint to get your own token. This endpoint is
// specific to the cobrowse.io hosted online demo. It will not work with your
// account and devices.
// You should fetch a token in an authenticated way from your own server for
// the user. See our documentation on generating a JWT for cobrowse:
// https://docs.cobrowse.io/agent-side-integrations/custom-iframe-integrations/json-web-tokens-jwts
const res = await fetch(
`https://cobrowse.io/api/1/demo/token?demo_id=${demoId}`,
);
const { token } = await res.json();
return token;
}

type WithCobrowseProps = {
demoId: string;
token?: string;
api?: string;
};

export default function CobrowseProvider({
demoId,
token,
api,
children,
}: PropsWithChildren<WithCobrowseProps>) {
const options: Record<string, any> = {};
if (api) options.api = api;
const [cobrowse] = useState<CobrowseAPI>(() => new CobrowseAPI("", options));

useEffect(() => {
console.log(`CobrowseAPI: api=${api} token=${token} demoId=${demoId}`);
async function setupClient() {
cobrowse.token = token || (await fetchToken(demoId));
}
setupClient();
}, [cobrowse, api, token, demoId]);

return <CobrowseContext value={cobrowse}>{children}</CobrowseContext>;
}
4 changes: 4 additions & 0 deletions share-links/src/DeviceLinkDemo.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.deviceList {
list-style-type: none;
flex: 1;
}
Loading