The corner bubble is the widest of the five places Refik answers: the only one that runs site-wide, and the only one that can open before a shopper asks it to. This page is about that one surface — where it sits, what it already knows when it opens, when it speaks first, and where it sends the question it hands on.
Of the five storefront surfaces, four are section blocks you drag into one template. This one is an embed, so a single switch puts it on the whole store. Three things follow from that, and each of them is a decision you can see in your own theme editor.
Turning it on
Shopify’s own panel
The bubble is one block in Refik’s theme app extension. You enable it from the app-embed panel in your own theme editor; Refik hands you a deep link to that panel and then stays out of it. The whole placement is that one switch, and a search of this codebase for the calls an app would need to reach a theme file comes back empty — the count is in the numbers below. The same fact runs backwards on removal: the surface belongs to the extension, so it leaves when the app leaves, and your theme is byte for byte what it was.
On opening
What it already knows
Because your theme renders the embed, the bubble opens knowing things a shopper would otherwise have to type: which page they came from, what is in their cart, which storefront language they are reading, and whether they are signed in. Someone standing on a product page can ask about it by pronoun. Being signed in is the one that changes the most, and the next card is why.
On identity
Their own order, and only theirs
Order, shipping and return answers open on the customer id Shopify itself signs into the request, which is a signature the panel has no way to forge. A guest can still find their own order with an order number and the matching address, and that route is deliberately rate limited inside a session, because order numbers run in sequence and a patient stranger would otherwise walk them.
Two rules travel inline with the block and both are there for a reason a stylesheet arrives too late to cover: one carries the vertical offset you set for phones down to the page root, and the other is a two-line lock that keeps the bubble invisible until its own styles have arrived. An unstyled panel flashing over your storefront for half a second is worse than a panel that appears a moment later.
Speaking first
It can open itself — once a visit, on a desktop.
This is the setting merchants ask about first and the one a widget is most often dishonest about, so here is the shipped state, exactly as it arrives. Two of the three openers are on out of the box. The budget is the interesting part: a visit gets one card, and the mark that spends it is shared by all three.
On out of the box
It introduces itself about fifteen seconds in, on a desktop, and stays quiet once the shopper has already opened the panel on that page
A mouse heading for the tab bar gets one card: help with what is in the cart, or, with an empty cart, a question about what they are after
Both sentences arrive already written, in every language the extension ships, and both are yours to rewrite or empty out
Off as it ships, or absent by design
A phone opens nothing by itself: the mobile switch ships off, and leaving-the-page is a mouse signal, which belongs to a pointer
The nudge while somebody reads a product page ships at zero seconds, which holds it back until you pick the seconds
One card to a visit, and an open panel holds the next one back
The one-per-visit mark lives in the browser, and where the browser refuses that write the card stays back — a budget we can count is the only budget we spend. Dismissing a card closes that card and ends the visit’s allowance, and the next visit starts with a fresh one. There is also a plain vertical offset for phones, so the bubble clears whatever your theme already floats in that corner, and the browser’s own bottom bar with it. It is a number you set, because that corner belongs to your theme and you are the one who can see what is already in it.
Plain numbers
Three numbers about this one surface
Read out of the app’s own build: three counts that a test in this repository recomputes from the extension’s own files on every run.
1
of the five storefront surfaces is an embed — this one. The other four are blocks you place inside a single template.
4
small files load with your page. The panel that does the talking waits behind them, in a template the browser neither downloads nor runs.
0
lines anywhere in this app that could write to a theme file. The search returns an empty set.
Source: the extension’s own files. The first number counts the blocks targeting the whole page, where the other four target a single section; the second counts the scripts the block attaches outside its deferred template; the third is a search of the entire codebase for the calls an app would need to edit a theme. A test in this repository recounts all three from those files and fails if this page and the code ever drift apart. The bubble also ships with eleven translation files, one per storefront locale — though the assistant itself replies in three languages, and writes in English with a line saying so when a shopper uses a fourth.
The handover
Handing a question over is the answer. Guessing is the failure.
This is the part of a chat widget usually left vague, so it is the part written out in the most detail here. Asking an assistant to admit the limits of what it knows is a line in a prompt, and a line in a prompt is a request. Three things behind it are enforced in code.
Before the answer
Every fact arrives from a tool call
A product name, a price and a stock level reach a shopper by way of a tool call, and by that route alone. When a search comes back empty, what the assistant is handed is an instruction beside the result: ask what they are looking for. It is also told to read a missing field as a gap in the tool result and to say so, because a confident sentence about the whole catalogue is what turns a gap into a wrong answer.
After the answer
The last check is in code
Before a reply reaches the shopper it is read by a checker that lives in the codebase, outside the prompt, because a rule written into a prompt is a request and this is a check. It looks for health claims, medical advice, certainty, a promise beyond your policies, manufactured urgency and a discount nobody authorised. A caught reply is sent back once to be rewritten; where the rewrite is caught too, a fixed line goes out in its place — that a reliable answer is out of reach here, and would you like this passed to the team.
Afterwards
It is filed as a gap
Whether a question was answered is decided from the content of the reply, and length was tried first: in production that test was wrong every time we checked it. A reply that ends in a question of its own counts as answered, because asking for the size is part of knowing it. Identical questions are folded together and counted, so what reaches you is a short list with the repeats visible, filed as missing knowledge.
Interface illustration, drawn from this page’s own account of the answer path — a product name, a price or a stock level reaches a shopper through a tool call and by that route alone, the drafted reply is then read by a checker that lives in the codebase rather than in the prompt, and a caught reply is sent back once to be rewritten. Only where that rewrite is caught too does a fixed line go out in its place. An empty search result arrives with its own instruction, to ask what the shopper is after. Nothing here is a measured figure: the answer rate and the named store are still the two placeholders further down.
What a handoff actually does
Writes one record for your team: what was discussed, what the shopper wants, and how to reach them
Stores one of three reasons — the shopper asked for a person, the assistant reached its limit, or your rules send this kind of request to a human
Takes the address from the account when the shopper is signed in, so it asks only for what it lacks
Asks for an address before it opens a record, so every record carries a way to reach someone
Carries a status your team moves through — new, being worked on, done — so one person owns it at a time
Three reasons, each read on its own, because “handoffs went up” covers two different events: the first of the three is a good handoff and the second is a gap worth reading. Where it lands depends on the clock — the console while your team is inside the hours you set, a record with the address on it outside them, so a question always lands in a window someone is watching. A handoff record is kept for thirty days.
What it is told to leave unsaid
A reply by e-mail from your team: that message goes out from your own tools, so the promise is yours to make
“Shortly”, or any other length of time, because the clock belongs to your team
On a return it says the request was submitted, and leaves approval to a person in your admin
The shopper’s own address read back to them, which stays on Shopify’s side of the request
A speed, a free return or a stock scare — those sentences are on a list the checker holds, in every language it answers in
The first two were in the product and were taken out after being measured against what the code does: text that promises past the code is worse than the gap it was covering. The sentence that offers a person comes from the server as a fixed string, in each language the assistant answers in, carrying your own support address.
The loop closes on the console side, and it closes in code. You write the answer to a question once; the matching from then on happens on the server, because a correction left to the model’s judgement is a suggestion. Publishing needs more than a save: the person doing it has to be an administrator and has to confirm they read the whole conversation and wrote the text themselves, and that confirmation is checked on the server, apart from the page that sent it. A draft Refik wrote for you publishes with the conversation it came from attached, because that transcript is where the evidence is visible. And once it is saved the same question is run past it again, so you are told whether the fix took. To read one conversation in place of a description of one, the recorded session prints each turn with the request that went out and the payload that came back.
Honesty
The evidence on this page, and the evidence still owed.
A page about a chat widget is an easy place to put an invented screenshot beside a figure from an invented store. So here is what stands behind each claim, and what is still owed.
A transcript, in place of a screenshot
The one recorded conversation sits on its own page as a transcript, with the request that went out and the payload that came back beside each turn, so it reads line by line. The illustrations here are drawn from the block’s own markup.
An answer rate from live stores
How often it answers on its own depends on your catalogue and on what your shoppers ask, so the figure belongs to a run of real stores.
A merchant willing to be named
A page about the surface a shopper touches is the last place to borrow somebody else’s name, so this page names no store yet.
Reply time is your team’s
How quickly a handed-over question gets a reply is a property of your team, so this page leaves that number to you. The product leaves it unsaid to your shoppers as well, which is the same decision written in two places.
Questions
What merchants ask about the bubble.
When does it first appear on my storefront?
After you switch the embed on in your theme editor, and after that switch alone. Installing the app and placing a surface are two separate decisions in that order, and you make both.
Can I run the bubble on its own?
Yes. The five surfaces are five separate blocks, and this is the one that stands alone most easily because it runs on every template. The other four are placed per template, so you can run this one on its own and add the rest whenever you choose.
Does it slow my storefront down?
Four small files load with the page. The panel itself — its styles and its modules — waits inside an inert template the browser neither downloads nor runs, and the starter builds it at the first sign of intent: a hover, a tap, or a few seconds of quiet. A click that lands before the panel exists is queued and replayed, and the queue is collapsed first, so two impatient taps open one conversation. Stylesheets are attached so they stay out of the first paint, with a plain fallback for a browser that has scripting turned off. The figure that decides this is Shopify’s own: it measures storefront performance before an app can be listed, and that measurement is the one that counts.
What does it do with a question about an order?
For a signed-in shopper it reads that shopper’s own order and shipping status, opened on the customer id Shopify signs into the request. A guest is asked for an order number and the matching address, and that route is rate limited within a chat session. It can open a return request the shopper asked for, and approval, refunds and the wording of your return policy all stay with a person in your admin — so it is told to say the request was submitted, because “accepted” would report a person’s decision before the person made it.
What decides whether an option can be offered?
Live stock, read at the moment of the answer: an option a shopper can buy is the only kind offered. Where the thing they want is unavailable it suggests the closest alternative, and it can register them for a notice when the original returns — after they have asked for that and given an address themselves. The sign-up is theirs to start.
Which languages does it actually work in?
Two different answers, and conflating them would be the easy way to sound bigger. The panel’s own text — buttons, labels, the line saying a shopper is talking to software — ships translated in eleven files, one per storefront locale. The assistant replies in three languages. A shopper writing in a fourth gets an English reply and, once, a sentence saying that is what is happening; it answers in the three its rules have been checked in.
Does the shopper know they are talking to software?
Yes. A line saying so ships on, already translated, as a sentence you can rewrite in your own words — clear it and the translated default returns in its place. There is also an attribution line under the panel; on the larger plans that one can be switched off.
What does the bubble store on my storefront?
A handful of values in the browser’s own storage, and each of them is worth naming: the conversation, so a reload keeps it; an identifier the browser generates for a guest, so a saved set can be found again; and the panel’s own preferences, like whether you left it as a bar or a circle. The bubble’s requests go to us and to Shopify, and that list ends there — it carries neither a pixel, an analytics tag nor a cookie. When a conversation turns into an order, Refik reads that from Shopify’s own order record: the chat writes a hidden cart attribute, the attribute survives into the order, and we read it back afterwards. The full account of what this app reads is on the security page.
Something here unclear, or contradicted by what you see in your own theme editor? That is a bug in this page and we would rather hear about it. The other four surfaces, and what each one refuses to do, are side by side on where it answers.