Live chat
The chat ends. What happened in it does not.
Most chat widgets are a good conversation and then a shrug. Somebody helped somebody, the tab closed, and a week later nobody can say who took it, what was promised, or whether the person on the other end was even a customer. Oneop works out which workspace the visitor reached before anything else happens, scores who should take them, and keeps the whole thread — the joins, the transfer, the close and who did it.
And because the chat is not a separate product, a visitor who proved who they were earlier in the conversation is still that person when a human arrives. Not copied across. The same conversation.
No credit card. Free plan, 2 seats.
5
Conversation statuses, validated as a closed vocabulary
3
Chats per agent at once before the router stops offering them one
0
Tickets created from a chat without a person deciding
1
Filter every visitor-facing transcript is projected through
10
Messages of the thread the reply suggestion is given, and no more
Four things happen between hello and goodbye
A chat looks like one event and is really four, and a widget that only does the first two is the reason support teams end up re-typing everything into another system afterwards. Recognise who is talking. Understand what the conversation is about. Get it to the right person. Keep what happened once it is over.
- The workspace is decided on the serverBefore a single message is accepted, the widget key is resolved to a workspace. A workspace sent by the browser is ignored, and a key that resolves to nothing is refused rather than defaulted.
- A reload rejoins rather than restartsThe visitor is reconnected to their most recent conversation that is not closed. One person refreshing three times is one thread, not three.
- The owner is chosen, not offered to everyoneDepartment queue first, then general; unavailable and at-capacity agents are removed before anyone is scored. With nobody free, the visitor is queued with a position and the team is told in a way that outlives being offline.
- The thread is the audit trailJoining, transferring, escalating and closing are written into the conversation as messages. What you read afterwards is what happened, in order.
Visitor connects
Widget key resolved to a workspace on the serverThread resumed or opened
Most recent conversation that is not closedOwner scored
Availability, capacity and load — or queued with a positionClosed and kept
Transcript, lifecycle messages, customer link
What is actually enforced in a conversation
Four mechanisms, in the order they happen to a visitor — and in two places, the boundary of the mechanism rather than a nicer sentence about it.
Fixed point 1
Anonymous, then known — and the difference is proof
A chat widget is the one place in your product where the person on the other side has not logged in. So it is worth being exact about which of the two columns below each thing falls into.
Decided on the server
- Which workspace this chat belongs toResolved from the widget key. The browser can send a workspace id; it is ignored. A key that resolves to nothing gets an authentication error, not a default.
- Whether an email address was provenA single-use code, mailed and returned within ten minutes, stored as a hash and rate limited. The verified address and the contact behind it are written onto the conversation and re-read from the database each turn, so nothing the browser sends can promote itself into an identity.
Taken as claimed, not as true
- The visitor identifierIt reconnects a person to their thread. It is not authority for anything, and it is never treated as one.
- A name or company typed into a formShown to the agent because it is useful, labelled as what the visitor said rather than as who they are.
- Live Chat does not resolve identity by itselfThe verification above is performed by the chatbot flow. Because it writes to the same conversation, an agent arriving later inherits it — but we are not going to claim the human side does something it does not do.
| What is held | Where it comes from | What it is trusted for |
|---|---|---|
| A visitor id from the widget | Sent by the browser | Thread continuity only — never authority |
| Which workspace this is | Resolved from the widget key on the server | A workspace sent by the browser is ignored |
| A verified email address | Only if a code was mailed and returned | Stored on the conversation, re-read every turn |
| The CRM contact behind it | Linked at verification | Carried into the chat with a person, not re-guessed |
Row two is the one a security reviewer asks about. If a widget takes the workspace from the page it is embedded on, anyone who can read your embed code can read your conversations.
Fixed point 2
What the human inherits when they pick it up
This is the part where a chat product that lives inside a CRM should be able to show its working, so here is the honest version rather than the flattering one. What an agent inherits is the conversation and everything already attached to it: the whole thread including the bot turns, the details the visitor gave, and — when the visitor proved an email address — the CRM contact that address belongs to.
There is also a quieter one that matters more than it sounds. If the conversation created something — a contact, a deal — that record was written down server-side as belonging to this conversation. A later turn can act on it without the browser being asked which record it meant, which is the difference between a chat that can safely update your CRM and one that has to ask you to do it afterwards.
What we are not going to tell you is that the agent screen is a three-hundred-and-sixty degree customer view. It is not. The console shows the thread and the visitor details, and the commercial record — orders, invoices, the full history — lives on the ticket screen and the contact record, one click away in the same product. Turning the chat into a ticket is what puts it all on one screen, and §4.4 says exactly how that works.
The thread
Who this is
Created by this conversation
Everything in this panel came with the conversation. Nothing in it was re-guessed from an email address at the moment the agent opened it.
Fixed point 3
Someone is given the chat. It is not shouted at the room.
Round-robin sends chats to people who have stepped away. A shared queue sends them to whoever clicks fastest, which over a week is the same person every time. Oneop picks an owner with a score: an agent with no live connection, an agent who is not online, and an agent already at their limit are removed before anything is ranked, and what is left starts at a hundred points, loses twenty for each conversation already open, gains ten for recent activity and gains thirty for being free when the chat is urgent.
Presence is a real state rather than a guess. Closing one of three tabs does not make an agent unavailable — availability turns on the last connection closing, and at that moment they are taken out of the assignment queue rather than left in it to be handed a chat nobody will answer.
And when nobody is available, the visitor is queued with a position and an estimated wait, and the team is alerted twice on purpose: a live broadcast to the agents who are connected, and a durable notification for the ones who are not. A broadcast alone would assume somebody is online, which is exactly the assumption that just failed.
| Situation | What happens |
|---|---|
| Two agents are free, one has three chats | The lighter one — each open chat costs twenty points |
| An agent is at their capacity | Skipped entirely, not merely ranked lower |
| A department is named on the chat | That queue is tried first, then the general one |
| An agent closes one of three browser tabs | Still online — presence turns on the last connection |
| Nobody is available at all | Queued with a position, and a notification that survives being offline |
| An agent transfers a chat to a colleague | Accepted as sent — the target is not checked |
The last row is a convenience, not a rule: transfer writes the new owner and puts the chat back into waiting, but it does not check that the person you named is still on your team. Worth knowing before you build a process on it.
Fixed point 4
A conversation can become a ticket. A person decides when.
Every message keeps its sender, its timestamp, whether an agent had read it and whether it was an internal note. The part worth pointing at is where the history of the conversation lives: not in a separate log, but in the thread itself. An agent joining, a transfer naming both people, an escalation, a status change and the close are all written into the conversation as messages, so reading it back is reading what happened rather than reconstructing it.
A conversation holds one of five statuses and nothing else — a bad one comes back with the list of the five — and once it is closed it refuses new messages instead of quietly accepting them. That is a real limit and we would rather state it: a closed conversation is a record, and continuing the discussion means a new one, or a ticket.
Which brings us to the boundary this page cares most about getting right. Nothing turns a chat into a ticket by itself. An agent asks for it; the ticket is seeded from the conversation, stamped with which conversation it came from, and from that moment it has an SLA deadline and your ticket automations running against it. Escalating is a different button that raises the status and notifies people and creates nothing at all.
| What is left | What is kept |
|---|---|
| The transcript | Every message, with its sender, its timestamp and whether it was internal |
| Who did what | Joining, transferring, escalating and closing are messages in the thread, not a side log |
| The status | One of five, and a closed conversation refuses new messages with a 400 |
| A ticket | Only if an agent asked for one — nothing creates it automatically |
| The customer link | The verified contact stays on the conversation, so it reads as their history |
Row four is the one to read carefully. Plenty of products describe this as chats "automatically becoming tickets". Here it is an action somebody takes, which is also why your ticket queue is not full of chats that said hello.
Connected with Oneop
The chat is a customer record before it is a conversation
A verified visitor is a CRM contact, not a session id. The ticket an agent raises from a chat carries the conversation it came from, and lands in the same queue as your email support. The chatbot that answered first and the human who took over share one thread, your automations can act on what happened, and the reporting reads the same rows rather than a separate analytics database. That is the whole argument for chat that lives inside the business system instead of beside it.
- CRMCustomer and commercial context follows the work.
- Help deskSupport sees the customer, commercial and operational history.
- AI chatbotAI responds using permitted business context.
- AI agentsAI acts on the same records people do, under limits that are published rather than described.
The other 7 modules sit on the same record, and reach Live chat the same way:
- SequencesOutreach works from CRM and customer context under controlled automation.
- Project managementSold work becomes delivery without rebuilding customer context.
- Inventory & warehouseSales and operations work from the same product and order context.
- ReportingEvery module is already a reportable dataset, so nothing has to be exported to be measured.
- FinanceOperational transactions continue into financial records.
- AI governanceWhatever AI touches in any other module is metered on the same path first.
- AutomationA trigger in one module can act in another without an integration between them.
Beyond the four
Internal notes that are structurally invisible
A note left on a conversation carries a flag, and the filter in §8 is what every visitor-facing path runs through. The agent sees the note in the thread; the visitor is not sent it, on any path, including a reconnect that replays the history.
A reply that arrives without a reload
The widget has no polling loop, so an agent reply is both written to the conversation and pushed down the visitor socket. Persistence is the source of truth and the push is best effort — a failed push loses a keystroke of latency, never the message.
The chatbot and the human on one thread
A bot conversation that hands off does not restart somewhere else. The same conversation gains an agent, and the handoff is a message in it. What the bot already established is what the agent opens with.
A suggested reply, drafted into the composer
Genuinely AI, and the only AI on this page. The model is given the last ten messages of the thread and returns a draft to the agent. It is metered against your workspace, so a run against a spent credit balance says so rather than failing quietly. It cannot send.
Both halves of the conversation in the shared inbox
Bot turns and agent turns are written by one function rather than two, which is why the thread you read in the inbox is the whole thread. A half-written conversation is the failure this design exists to prevent.
Unread that means unread
The badge counts messages from the visitor that an agent has not read — not internal notes, not your own replies, and computed on the server rather than in the tab you happen to have open.
The suggested reply is the only AI on this page. How the models are governed, metered and constrained is one page: AI governance.
Where the widget goes, and where the conversation ends up
The widget is a script tag, so it goes on the site you already have — a WordPress install, a storefront, an app shell. The connections that matter more are on the other side: the store the order came from, the CRM the contact lives in, and the mailbox and channels your team already watches when a chat needs somebody who is not at their desk.
See all integrations- WordPress
- Shopify
- WooCommerce
- HubSpot
- Google Workspace
- Microsoft 365
- Slack
- Webhooks
For the technical evaluator
An internal note cannot reach a visitor, because there is exactly one place that decides what a visitor may see.
Not a rule each endpoint remembers. A single projection that every visitor-facing transcript path runs through — which exists because remembering it failed twice.
Why that is one function and not a habit
The two failures. The first was an endpoint that returned the conversation's rows to the widget exactly as they came out of the database, internal notes included. A real note about a customer reached the customer it was written about. The fix filtered that one route inline, which felt like the end of it.
It was not. A later feature added a second visitor-facing path — replaying history to a widget that reconnects — and guarded it by checking whether the message came from an agent. That reads correctly and is wrong: an internal note is written by an agent, so the guard let every one of them through. The same leak, on a different line, in code written by someone who knew about the first one.
What replaced it. One exported predicate and one projection function that filters a transcript with it, and the standing rule that no visitor-facing surface reads the conversation rows directly. The agent console still gets everything, because it needs to. The predicate is written so that only an explicitly non-internal message passes, which means a message row with the flag missing or null is withheld rather than sent — and so that any future staff-only flag is added in one place instead of at every call site that would have to remember it.
Why this is the guarantee we surface. Because the failure mode is silent. A leaked internal note does not throw, does not appear in an error rate and does not show up in a demo; you find out when a customer quotes your own note back at you. The only durable defence against that is structural — make the safe path the only path — and it is fair to ask a vendor to show you where that structure is rather than to describe their care.
Scope. Conversations, messages, visitor records, agent assignment and the notifications raised from them all carry the workspace they belong to, and the workspace on a chat is resolved from the widget key on the server rather than accepted from the browser. Agent-facing conversation routes check the workspace on the record before they read or write it. One honest note on the boundary of that: the check sits in the route layer rather than in the update helper itself, so it is enforced on every path that exists and is not made structurally impossible the way the visitor filter is.
What it costs
Live chat, the chatbot on the same widget, the shared inbox and turning a chat into a ticket are on every plan including Free. The last row is a plan allowance rather than a barrier: it is the number of concurrent conversations your plan is sized for, and the widget does not currently turn a visitor away when you are over it. The limit that is enforced is the per-agent one — an agent at capacity is skipped by the router, which is what makes a busy queue queue.
See full pricing| Plan | Live chat | Chatbot on the same widget | Shared inbox | Turn a chat into a ticket | Concurrent chats on the plan |
|---|---|---|---|---|---|
| Free $0 | Included | Included | Included | Included | 2 |
| Starter $19 | Included | Included | Included | Included | 5 |
| Pro $59 | Included | Included | Included | Included | 15 |
| Business $129 | Included | Included | Included | Included | 50 |
Frequently asked
What does Oneop know about a visitor before they tell you who they are?
Less than you might expect, and that is the honest answer. It knows an identifier the widget generated, which is used to reconnect the same person to the same conversation and for nothing else. It knows which workspace the chat belongs to, and that one it works out itself from the widget key — a workspace id sent by the browser is ignored, which is what stops one site embedding another company’s widget key and reading their chats. It knows the connection address and where the chat was opened. Anything else — a name, an email, a company — is there only because the visitor typed it or a flow collected it, and it is shown to the agent as something claimed rather than something proven.
How does a visitor become a known customer?
By proving it, and only by proving it. If the conversation asks for an email address, a single-use code is mailed to it and has to come back within ten minutes; codes are stored hashed, attempts are limited, and the reply never reveals whether an address is on file. When it succeeds, the verified address and the CRM contact behind it are written onto the conversation itself and re-read from the database on every later turn, so nothing the browser sends can promote itself into an identity. That verification is performed by the chatbot flow rather than by the live chat handler — but because it is the same conversation, an agent picking the chat up afterwards inherits it instead of starting again.
What decides which agent gets a chat?
A score, computed at the moment the chat needs an owner. If the chat names a department, that queue is tried first and the general queue second. An agent with no open connection, an agent who is not online, and an agent already at their concurrent limit are removed before scoring rather than ranked below it. What is left starts at a hundred points, loses twenty for each conversation already open, gains ten for having been active in the last five minutes, and gains thirty for being free when the chat is high or urgent. The highest score takes it. If nobody qualifies, the visitor is queued with a position and an estimated wait, and the alert that goes out is a durable notification as well as a broadcast — because a broadcast only reaches the agents who are already connected, which is precisely the wrong assumption to make when the problem is that nobody is.
Is there a limit on how many chats can run at once?
Two different things get called that, so it is worth separating them. Per agent, yes and it is enforced: an agent at their concurrent limit — three by default — is skipped by the router entirely, which is why a busy team queues rather than quietly overloads one person. Per workspace, your plan records an allowance, and you can see it in the table above, but the widget does not currently turn a visitor away when you are over it. We would rather write that down than let a number in a pricing table imply a refusal that does not happen.
Does a chat automatically become a support ticket?
No, and this is the sentence most worth reading twice. Turning a conversation into a ticket is an action an authenticated agent takes: the ticket is seeded from the conversation, stamped with the conversation it came from, and from that point it is a real ticket with an SLA deadline and the created-automations run against it. Escalating is a different action with a different button — it raises the conversation’s status and notifies people, and it creates nothing. Marketing copy in this category loves the word "automatically". Here a person decides, every time.
What happens to the conversation after it is closed?
It stays, whole. Every message keeps its sender, its timestamp and whether it was an internal note, and the lifecycle is inside the thread rather than beside it: the agent joining, a transfer naming both people, an escalation, and the close naming who closed it are all messages you can read in order. A closed conversation refuses new messages rather than silently accepting them, so the transcript is a record of what happened and not a document that keeps changing. If the visitor verified themselves, the contact link stays too, which is what makes it read as that customer’s history later rather than as an anonymous session.
Which parts of this are actually AI?
One. An agent can ask for a suggested reply, and the model is given the last ten messages of the thread and returns a draft into the composer. It is metered against your workspace’s AI credits, and if you are out of credits you are told so rather than handed a silent failure. It cannot send, and nothing sends on its own. Be aware of one boundary: those ten messages are the last ten in the thread, internal notes included, so treat a note in an active chat as something a draft may have read. Everything else here is ordinary software — the routing score is arithmetic, the queue is a list, and the unread badge is a count.
Put a chat widget on your site that leaves something behind.
One script tag is the whole install. Or book a walkthrough and we will show you a visitor proving who they are, a chat scored to the right agent, and a closed conversation you can still read a month later.
Free forever · 2 seats · No credit card