iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Hao Xu built Invosmith, an invoicing tool for freelancers and small service businesses, and wrote up the decisions in a DEV Community post dated October 2. The most useful lesson is about what an invoice tool can honestly claim. Invosmith’s “Viewed” event means a client opened the hosted invoice page from the emailed link. It does not mean the client read the email or the invoice. Xu’s choices around that signal, around Stripe Connect payment routing, around private payment URLs and around analytics volume each carry a trade-off, and this article walks through them in that order.
What a “Viewed” event actually proves
Freelancers mostly want one answer: has the client seen the invoice? Xu’s first instinct was the common approach of embedding a tracking pixel in the email and recording when the image loads. He rejected it because Apple Mail Privacy Protection and corporate email scanners can fetch remote images automatically. A pixel then records an open that no person performed, and a freelancer may conclude a client has seen an invoice when nobody has.
Xu’s argument is that a false positive is worse than no signal at all. In his words: “That’s worse than no tracking: the user stops chasing a client who never saw the invoice.”
Invosmith therefore ties “Viewed” to a different action: the client clicks the link in the email and loads the hosted invoice page. That is a narrower claim, and it is the one the product makes.
| Signal | What triggers it | Limitation Xu identifies |
|---|---|---|
| Email open pixel | An embedded image loads in the mail client | Automated fetches by mail privacy features and corporate scanners can fire it without a person opening the email |
| Hosted invoice “Viewed” event | The client opens the hosted invoice page from the emailed link | Shows a page visit only. It does not prove the email was read or the invoice contents were read |
For follow-up decisions, the practical difference is that a page visit is a deliberate action by someone who reached the page. It is still weaker than a payment, so a freelancer should treat “Viewed” as a reason to follow up politely, not as confirmation of receipt.
How Invosmith takes payments without holding client funds
Xu’s payment design uses Stripe Connect. He reports Standard connected accounts with Stripe-hosted onboarding, and direct charges created on the freelancer’s connected account. Under that arrangement the money settles to the freelancer’s own Stripe balance. Xu’s own Stripe account sees only his subscription revenue from Invosmith.
He treats the boundary as a testable requirement. His stated acceptance test is: “if an invoice payment ever shows up in my own balance, the architecture is wrong.”
Rank #2
Direct charges on connected accounts
With direct charges, the payment is created on the connected account, so the freelancer is the merchant of record for that invoice. The platform is not a pass-through for client money, which is the point of Xu’s acceptance test. This is one implementation that Xu describes, and it is not a universal Stripe setup. Your own account type, onboarding flow and fee handling should be confirmed in Stripe’s current Connect documentation before you build.
Xu also says his concern about money-transmitter licensing shaped this design. That is his rationale for the architecture, not a legal conclusion. Whether a given model triggers licensing depends on jurisdiction and business structure, so ask a lawyer who handles payments in your market before relying on it.
Keeping webhooks separate
Xu recommends keeping the product’s own billing webhooks apart from the webhooks for connected-account activity. He also selects webhook events one at a time instead of subscribing to everything, which avoids receiving legacy event types you do not handle. The practical effect is that a bug in invoice-payment handling cannot be confused with a subscription event, and vice versa.
Rank #3
- Income And Expense Log Book: This Income and Expense Record Book(8.5" x 10.5") is a necessary item for any small business owner or entrepreneur. It is an essential part of any business - helping you understand your overall earnings to determine if you are profitable.
- Daily Tracking and Weekly Overview: let our log tell you if you are profitable today! There are two pages per week to help you you track your income and expenses. At the end of each day or week, you can note whether you made a profit or a loss for the day.
- Clear P&L Statement For Your Business: This income and expense book makes it easy to see your expenses and how they fluctuate from time to time. This makes it easy for you to decide where you can cut back on expenses and assess your total annual net profit.
- Main Features: Expense Review + Income Review + Weekly Pages + Summary of The Year + Twin-Wire Binding + Waterproof Cover + Rounded corner design + Thicker paper
- Effective Organization: This budget book has a twin-wire binding and you can easily lay it flat at 180°. This effective design can help you work better and bring you great convenience in the process of using.
Private payment links: the URL is the credential
Clients on Invosmith have no account. The invoice link is therefore the only thing that grants access to the invoice and its payment page. Anyone who holds the URL can use it, which makes the URL a bearer credential. Xu’s controls are designed around that fact:
- Invoice pages and payment flows run on a separate pay subdomain, away from the marketing site.
- Each link uses a long random token, not a sequential invoice ID that could be guessed.
- Reads are scoped server-side, so a request is answered only for the owner account or the matching client token.
- Responses are sent with no-store caching, so intermediaries and browsers do not keep copies.
- Session cookies are kept off the marketing site, so a session on one host does not leak to another.
- Pages carry noindex and robots.txt rules to keep them out of search results.
Xu is explicit about the last item’s limits. “But noindex is the floor, not the security model.” Robots directives ask well-behaved crawlers not to index a page. They do not stop anyone who has the link, and they do not stop crawlers that ignore them. Authorization has to be enforced on the server, which is why the token and the scoped reads matter more than the indexing tags.
Keeping analytics lean
Xu runs analytics in a separate Cloudflare D1 database, not in the transactional database. He keeps a small, fixed event vocabulary in code and rejects any event name that is not registered. Each event’s properties are constrained to five parameter categories.
Rank #4
The post leaves the names of those five categories unfinished, so this article does not list them. Anyone copying the pattern will need to define their own categories rather than assume Xu’s.
His stated reason is to limit growth. Every new event name or property combination adds rows and query shapes that must be stored and read back, and a small product gets little benefit from that complexity. The guardrails he describes are:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →- A separate analytics database, so reporting queries do not compete with product writes.
- A registered event list kept in code, so an unknown event fails instead of being stored.
- A fixed, small set of allowed properties per event, so cardinality stays bounded.
Using Search Console to choose what to publish
Xu pulled impressions, clicks and average position by query and page through the Search Console API. The data showed him that the head term “invoice generator” was crowded. He reports a keyword difficulty of around 65 for it, while some long-tail terms scored in single digits. His product therefore focused on vertical invoice-template queries, which match specific freelancer trades more closely than a generic generator page does.
Best Value
These difficulty figures and the roughly 1,000 rows he exported from the Search Console interface are Xu’s own readings from his tools in 2026. They were not independently verified and do not come from a published benchmark dataset, so treat them as one builder’s observations and check current numbers for your own niche.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.What local tests missed: a D1 query limit
The most instructive failure in the post is a runtime problem. A dashboard query in Cloudflare D1 failed. The query combined seven SELECT statements with UNION ALL. The same codebase passed all 992 local tests, which ran against SQLite. The local tests did not exercise D1’s behavior with that query shape, so the failure reached the dashboard before anyone saw it. Xu’s report describes this outcome; the article does not claim a specific D1 limit value.
His fixes were:
- Split the large compound query into smaller queries.
- Make each dashboard card load independently, so one failing query does not blank the whole dashboard.
- Add a test that rejects compound SELECT statements above a set size, so the problem is caught before deployment.
The broader lesson is that a local test suite proves behavior on the engine it runs against. If production runs on a different engine, the query shapes that matter need checking on that engine, or at least a test that flags risky shapes before they ship.
Quick Recap
Checklist before copying these patterns
- Define “Viewed” in your own product as a page event, and say so in the interface.
- Confirm your Stripe account type and charge model in current Stripe Connect documentation before writing payment code.
- Get jurisdiction-specific legal advice on whether your money flow creates licensing obligations.
- Treat invoice URLs as credentials: long random tokens, server-side scoping, and no-store responses.
- Register analytics events in code and reject unknown names.
- Run any production-database query shapes on the production engine, not only in local tests.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

