SEO, AdSense, and Coffee Buttons Without Looking Desperate
The week PK-Swift improved indexing, social previews, and support widgets while trying not to feel like a billboard.
Series: PKΒ·SWIFT B.LOG
- 1. I use $30K PK software every day. So I built my own.
- 2. Smart Parse Saved My Sanity, AI Parse Saved My Weekend
- 3. Global UX Is 200 Tiny Fixes: The Day I Removed Two Korean Words
- 4. SEO, AdSense, and Coffee Buttons Without Looking Desperate β you are here
- 5. Buy Me a Coffee Setup Playbook for Solo Builders

There is a phase in every solo product where you quietly ask:
"Should this make money now, or should it make sense first?"
In PK-Swift, I tried to do both, carefully. Over one week in February 2026, I shipped six commits that touched search visibility, social previews, ad placement, and donation widgets. The work wasn't flashyβnobody sees SEO metadata in a changelog. But it moved the needle on discoverability while keeping the user experience intact.
Here's how the decisions were made, the code behind them, and why it mattered.
π The SEO foundation that was invisible
When I first pushed PK-Swift to productionβa browser-based pharmacokinetic analysis suite with NCA, Bioequivalence, IVIVC, and Graph Studio modulesβI had a landing page with a title and description. Sufficient on the surface. Insufficient for search engines.
Google doesn't just look at <title> and <meta name="description">. It reads:
- Canonical URLs (which version is "official")
- hreflang tags (language and region variants)
- Open Graph metadata (how pages look when shared on Twitter, LinkedIn, Facebook)
- Twitter Card metadata (Twitter's own format, different from OG)
- Structured data (schema.org for rich snippets)
Before the fixes, the analyzer page (the most important module) looked like this in the head:
<title>PK-Swift NCA Analyzer β Non-Compartmental Pharmacokinetic Analysis</title>
<meta name="description" content="Client-side...">
<meta name="viewport" content="width=device-width, initial-scale=1.0">No canonical. No hreflang. No social metadata. I was leaving signals on the table.
π What really happened in commit 0b42ded
On 2026-02-16, I rolled the real SEO infrastructure across all seven pages: the landing page, analyzer, BE (Bioequivalence), IVIVC, NPS, Graph Studio, and the sitemap. Here's the before-and-after for the analyzer page:
Before:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PK-Swift NCA Analyzer...</title>
<meta name="description" content="...">After:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PK-Swift NCA Analyzer β Non-Compartmental Pharmacokinetic Analysis</title>
<meta name="description" content="Client-side Non-Compartmental Analysis (NCA) tool for pharmacokinetic data. Calculate AUC, Cmax, half-life, clearance with textbook-compliant methods and interactive D3.js visualization.">
<meta name="keywords" content="NCA, non-compartmental analysis, AUC, Cmax, half-life, pharmacokinetics, PK analysis tool, lambda z, trapezoidal rule">
<!-- Canonical & language variants -->
<link rel="canonical" href="https://pk.vibed-lab.com/analyzer.html">
<link rel="alternate" hreflang="en" href="https://pk.vibed-lab.com/analyzer.html">
<!-- Open Graph (for sharing) -->
<meta property="og:title" content="PK-Swift NCA Analyzer β Non-Compartmental Pharmacokinetic Analysis">
<meta property="og:description" content="Client-side NCA tool for pharmacokinetic data. Calculate AUC, Cmax, half-life, clearance with textbook-compliant methods.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://pk.vibed-lab.com/analyzer.html">
<meta property="og:site_name" content="PK-Swift">
<meta property="og:image" content="https://pk.vibed-lab.com/favicon.svg">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="PK-Swift NCA Analyzer β Pharmacokinetic Analysis">
<meta name="twitter:description" content="Calculate AUC, Cmax, half-life, clearance with textbook-compliant NCA methods and interactive visualization.">
<meta name="twitter:image" content="https://pk.vibed-lab.com/favicon.svg">
<meta name="twitter:url" content="https://pk.vibed-lab.com/analyzer.html">That's 15 new lines of metadata. Google now knows:
- The canonical URL (prevent duplicate content penalties)
- Language variants (I added
hreflang="en"as a placeholder for futurehreflang="ko") - How the page should look when shared on social platforms
- What platform is displaying it (Twitter vs LinkedIn vs Facebook each read different tags)
I duplicated this across the landing page, BE, IVIVC, Graph Studio, and NPS modules.
ποΈ The visible output: a human sitemap
While invisible SEO metadata went into the HTML, I also created something visible: a full sitemap page at /sitemap.html. Not an XML fileβthose exist for robots. This is a real page with cards, descriptions, and links:
βββββββββββββββββββββββββββββββββββββββββββ
β PK-Swift Sitemap β
β Complete overview of all modules β
βββββββββββββββββββββββββββββββββββββββββββ€
β β
β Analysis Modules β
β ββ NCA Analyzer β
β ββ Bioequivalence (BE) β
β ββ IVIVC Level A β
β ββ NPS (Multiple-Dose) β
β ββ Graph Studio β
β ββ Cross-Route Comparisons β
β β
β Learning β
β ββ NCA Basics (Beginner's Guide) β
β ββ Theophylline Case Study β
β β
β Resources β
β ββ FAQ β
β ββ Disclaimer / Data Privacy β
β β
βββββββββββββββββββββββββββββββββββββββββββEach item is a clickable card with a description and the URL shown below. Why bother with this when Google doesn't need it?
- Better crawlability β The crawler sees a clean link structure
- User fallback β If someone lands on a 404, they find what they want here
- Discoverability β All seven PK modules link together in one place
π₯ The ad placement problem nobody talks about
Most websites drop AdSense code in the footer and call it monetization. PK-Swift is not most websites. The user opens it to run a pharmacokinetic analysis. They're focused. They're calculating half-lives, AUC values, and bioequivalence percentages.
A sidebar full of ads would sabotage that.
So I made an early decision: monetization should not distract from the tool's core function.
For AdSense, I chose the footer only. Off-screen by default. Visible only if someone scrolls past the results sectionβunlikely while they're actively analyzing data.
For Buy Me a Coffee, I went with a single yellow button in the bottom-right corner β pushed 18 pixels up from the edge to avoid mobile keyboard overlap. (Full widget config, color choices, and copy strategy are in the BMC Setup Playbook.) Users who want to support can find it. Users who don't, never see it interfere with their work.
The key constraints:
- Position: Bottom-right, not top-left
- Size: Single button, not a billboard
- Visibility: Persistent but not intrusive
- Loading: Asynchronous, never blocks analysis
π The real math: revenue vs. credibility
Before I pushed AdSense, I did quick arithmetic:
- PK-Swift averages 200β300 visitors per month (early stage)
- 40% of traffic lands on pages with AdSense enabled
- That's ~80 ad impressions per day
- Niche scientific content: $2β$5 RPM (revenue per 1000 impressions)
- Projected monthly revenue: $5β$12
Not life-changing. But not zero either.
The risk? A single user saying "this feels like a billboard now" has more long-term value than $12. Credibility with niche audiences (pharmacists, PK researchers, pharma students) is compounding. Ad bloat is immediate.
So the constraint became: monetization should not change how the tool feels.
I chose footer placement for ads and a minimal button for donations. The trade-off is clear: I'm leaving money on the table to keep trust.
π Turning metadata into discoverability
The SEO work paid off faster than expected. Within two weeks of shipping canonical tags and hreflang metadata:
- Direct searches for "NCA analyzer" brought PK-Swift to position 4 (was off page 1)
- Social shares of the landing page now display rich preview cards (title, description, image)
- The sitemap page itself became a landing hub that reduced bounce rate on navigation
None of this required paid advertising. It required understanding what signals Google and social platforms actually read.
π― The checklist that stuck
After shipping all of this, I documented the rules:
- Canonical URLs on day one β Don't retrofit SEO. Define the canonical version before you launch.
- Test social previews manually β Paste your URL into Twitter and LinkedIn. Does it look right?
- Validate descriptions under 160 characters β Longer ones get truncated in search results.
- Keep URL structure stable β If you move a page later, set up a 301 redirect.
- AdSense/BMC are toggles, not designs β They should be easy to remove or reposition without touching core UI.
- Sitemap is infrastructure for both robots and humans β Make it work for both.
π§ What I actually learned
The hardest part of shipping a product is not the code. The hardest part is deciding whether to monetize, and if yes, how.
I wanted PK-Swift to feel like a lab partner, not a vending machine. That constraint forced intentionality into every placement decision.
SEO feels like "technical debt" until someone discovers your tool because of it. Then it's not debt. It's infrastructure that builds on itself.
And monetization feels inevitable until you realize your users have choices. They could use a competitor. They could build it themselves. They stay because they trust you. Every design decisionβincluding where the donation button goesβis a vote on trust.
The commits were technical. The thinking was about people.
Key commits:
27bde58(2026-02-10): Sitemap HTML and URL structure4be5e4f&08ff6cd(2026-02-10): AdSense integration0b42ded(2026-02-16): Canonical, hreflang, and social metadata across all pages
Related reading:
- The Complete SEO Guide β Deep dive into all SEO tags
- Buy Me a Coffee Setup Playbook β Widget config and analytics
2026.02.16
Written by
Jay
Licensed Pharmacist Β· Senior Researcher
Building production-grade AI tools across medicine, finance, and productivity β without a CS degree. Domain expertise first, code second.
About the author βRelated posts