Tonkeeper integration fails at transaction signature
The user reaches confirmation in the wallet — and the flow stops there. Transaction signing does not go through: the wallet window closes, the button was pressed, and the app keeps waiting for a response that will never come.
To the user this looks like "nothing happened"; to the business, it looks like an abandoned scenario at the final step.
A separate problem is losing the wallet session when the page is refreshed or the user follows a link inside the app.
The bridge between the tab and the wallet breaks, and wallet connection to the app has to be started over; on mobile, where the user returns from the wallet app, this happens most often, and not everyone makes it to signing again.
Worst of all, wallet connection errors are indistinguishable. User rejection, an expired request, a network mismatch, and a connection loss produce the same log entry.
Support receives a stream of identical tickets without a clear reason, and engineers cannot separate an integration failure from human behavior — and fix things by guesswork.
All of this is about stitching states together: the signature request, the session, and network events must converge at a single point; otherwise Tonkeeper integration falls apart for no apparent reason. We break down how this is addressed.
What changes after connecting the wallet to the service
Share of confirmed transactions and repeat logins
After Tonkeeper integration via TON Connect, the signature is verified before sending to the network, so the user does not enter the "signed — rejected — signed again" loop.
The share of successful confirmations grows because the service knows the address, network, and balance in advance and does not offer an action that will obviously fail.
Repeat logins become faster: the saved connection requires one confirmation instead of a full handshake from scratch.
Time to connect a new user
First login is the most expensive point in the funnel, and we remove unnecessary steps from it: wallet selection, return to the service, and confirmation follow one scenario, while the connection state is restored after page reload.
In practice, the path is reduced to two or three actions, and the main reason to abandon connection midway disappears.
Classes of failures that stop reaching support
We separately define the list of failures handled on the integration side: rejected signature, stale connection, wrong network, user-cancelled confirmation, address mismatch.
Each gets a clear message and retry without losing progress, and signature reliability is confirmed by validating the wallet response. Previously, such tickets reached support as "won't connect" — now they do not reach the user.
Wallet connection modes and their technical limitations
The connection mode determines not convenience, but where the private key remains and which confirmation channel the user gets.
All options rely on a single standard supported by Tonkeeper, so changing the mode does not require rewriting the app logic — only the return after signing changes.
In a desktop browser, the app initiates a session, the wallet confirms it and signs each operation: the key never leaves storage, and the app receives the address and signature.
On a phone, a mobile browser limitation gets in the way — switching tabs and returning breaks the session, so confirmation is moved to a separate window.
| Option | When it fits | Limitations |
|---|---|---|
| Wallet in a desktop browser | Main scenario of a web app | Mobile login not covered |
| Mobile browser | Quick login from a phone | Switching tabs breaks the session |
| Confirmation in a separate window | Mobile browsers | Depends on correct return via link |
| Two-device pairing | QR login: display on desktop, sign on phone | Both devices and a stable network required |
| Signing without an external wallet | Tests, automation, service operations | Key in the app — higher storage requirements |
A common mistake is choosing a mode by the look of the button rather than by where the key lives and how the user returns, notes our engineer.
On a phone, confirmation in a separate window most often breaks on return: the session is created, but the result does not reach the app, and the user thinks the wallet did not connect.
Workflow: from scenario analysis to handover
We structure the connection implementation so that each step relies on the previous one already verified.
We start not with code, but with analysis of user scenarios and current failure points — otherwise Tonkeeper integration via TON Connect turns into trial and error on real users.
- User scenario analysis. What the user does from login to operation confirmation, where they return from the wallet, at which step they close the window. We record failure points from logs and support tickets.
- Wallet interaction scheme. What goes to the wallet, what comes back, where session state is stored, and how the app knows the connection is still alive.
- Setting up connection and response handling. We bind the response to a specific operation, not to the last opened one — otherwise a repeat login creates a duplicate action.
- Handling signature failures and retries. We separate user rejection, a closed window, an expired session, and network loss: each has its own message and behavior.
- Pre-release verification. What exactly we consider passed — below.
- Handover and team training. Code walkthrough, diagram, and instructions for common failures so fixes do not require us.
Pre-release verification
We run scenarios on real wallets and browsers, not only on the internal staging environment: return from the app, rejection of signing, reconnection, account switch. We make sure a repeated request does not execute the operation twice and that the session closes correctly. Rollout goes to a share of traffic; rollback restores the previous build.
What we hand over after Tonkeeper integration
We deliver the integration not as a set of one-off fixes, but as a package that lets the team change the connection, investigate user tickets, and verify releases without us. Below is what remains in the repository and the internal knowledge base at handover.
Artifacts for engineers
- Working connection configuration: list of supported wallets, network parameters, and app address — the connection is reproducible from the repository, not from messenger chat.
- Wallet connection documentation: entry points, methods used, and the procedure for restoring the session after page reload and device change.
- Signature flow diagram: from request creation to return of the signed message, with marked places where the wallet address and request lifetime are checked.
- Rules for handling failures and retries: which errors are considered temporary, how many attempts we make, with what interval, and when we prompt the user to reconnect.
- Logging of connection events in a unified format: session ID, wallet, stage, result, error code — ticket investigation takes minutes, not a day of back-and-forth.
- Self-check checklist after changes: a short sequence of steps before rollout so frontend updates do not break the signing scenario.
Guide for support
- Instructions for common tickets: connection button not visible, signature not going through, session dropping after page reload.
- A "symptom — cause — action" table with a link to the relevant log entry so first-line support can close tickets without escalation.
- Responsibility boundaries: what support resolves on its own and what goes straight to engineers, with ready-made wording for the user response.
Case study: failed signature share dropped from 12% to 2%
A service with user action confirmation made Tonkeeper wallet the main login method.
Confirmations were lost for no apparent reason: the user went to the wallet, returned in a different tab or from another device, the page had time to refresh — the signature state reset, and outwardly it looked like "pressed and nothing happened."
What we changed
We moved signature state to the service side and bound the request to the user and device.
Failure reasons became distinguishable: rejection by the user, expired request, technical failure — instead of one vague "confirmation error." A retry starts from the same screen, without leaving the scenario, and support receives a ready cause code.
| What we look at | Before | After |
|---|---|---|
| Failed signature share | 12% | 2% |
| Failure reason | manual log investigation | visible immediately and unambiguously |
| Retry | entering the scenario again | from the same screen |
| Support tickets | each one investigated manually | closed by cause code |
The failed signature share dropped from 12% to 2%, and ticket investigation stopped taking engineering time.
"Previously we could not tell the user what exactly happened — now the reason is visible in the first line, and the retry goes through without leaving the scenario," says the head of the department.
How does a browser wallet differ from a phone wallet?
A browser extension and a mobile wallet are two different session lifecycles, and the same integration code behaves differently in them.
The extension lives in the same context as the page: the connection opens and closes with the tab, and the response arrives in the already established channel.
Mobile Tonkeeper is a separate app, and a gap appears between the page and the wallet that does not exist in the browser.
The difference becomes critical when returning the result. The extension returns the address or signature directly to the open tab, and the page simply waits.
The mobile scenario requires leaving the page and returning via a link to the app address — here the system may unload the tab, and the user may return after the wait timer expires.
User interruption also looks different.
In the extension, rejection at confirmation is an explicit event: the page receives it and moves the state to "rejected." On a phone, the user simply closes the wallet, and nothing reaches the app: the request is not rejected but left hanging, and without an explicit error it is easy to mistake it for successful.
This is addressed by a unified connection scheme: a common interface for connection, signing, and sending; a status model where waiting, confirmation, rejection, and session loss are different states; and recovery by the saved request ID. Then the browser wallet and phone wallet follow one path, and only response delivery differs.
Technical concerns about wallet connection
Engineering concerns about connection come down to compatibility: what to do with those who already logged in via the old scheme, and who is responsible for changes on the wallet side. We address them point by point.
Some users are connected via the old scheme — will we have to log them out?
No. Both schemes live in parallel: the session record stores a connection version flag, and on login the app determines which path to take the user down. We make the transition lazy — on the next action — without forced logout and repeated wallet confirmation. The share of successful connections during the transition does not drop.
Is a separate service needed to verify the signature?
For a single app — no: the signature, confirmation lifetime, and one-time code are verified where the data is received. A separate verifier service is justified when verification is shared across multiple apps and a unified list of active keys is needed. Moving it out "just in case" adds an extra point of failure in the login chain.
Can multiple wallets be kept at the same time?
Yes. We store a list of connected wallets with a default active one, not a single address: a user with two devices switches without repeated confirmation, and the status of the others is preserved. It works with Tonkeeper and other supported wallets in one scenario.
Who is responsible for updates if the wallet changes something on its side?
Changes arrive as a new version of the connection protocol, so we maintain an adapter and monitor announcements on the wallet side. We check compatibility with a matrix of supported versions and run the connection scenario on each one before release, not based on complaints.
If backward compatibility breaks, we update the adapter, and the previous scenario remains working until planned shutdown.
Let's discuss the task: connecting a wallet to your service
To come back with an estimate and work plan rather than generalities, we need a minimum of inputs.
Let's discuss the connection task — these points immediately show the scope: how many confirmation scenarios to cover, how many wallets and devices to support, and where the logic currently breaks.
- Confirmation scenario description: what exactly the user signs, at what moment, and what the service does before and after signing.
- Supported wallets and devices: Tonkeeper as the main reference, plus a list of other apps and platforms where the scenario must work identically.
- Current failure points: where connection has already been tried and what fails — return from the app without a response, session loss, repeated signing.
- Expected behavior on failure: whether the user stays in the service, whether they can retry, and what support sees on their side.
- Rollout timeline: by what date a working scenario is needed and whether there are hard dependencies on related work.
- Constraints: security requirements, access to the test environment, and the process for handling real operations.
Then our part: we analyze the scenario, agree on failure behavior, and send an estimate and work plan with stages and acceptance points.
The client describes how this looks in practice more precisely: "They did not just hand over code — they analyzed our scenarios, showed where we lose users, and stayed in touch after rollout." Describe the task — we will come back with an estimate and a plan.







