<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: dalin zhou (钱先生)</title>
    <description>The latest articles on DEV Community by dalin zhou (钱先生) (@dalin_zhou_e8f17ca6).</description>
    <link>https://dev.to/dalin_zhou_e8f17ca6</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4173430%2Fc840c530-346c-44c1-a81a-90b63786316a.png</url>
      <title>DEV Community: dalin zhou (钱先生)</title>
      <link>https://dev.to/dalin_zhou_e8f17ca6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dalin_zhou_e8f17ca6"/>
    <language>en</language>
    <item>
      <title>Weekends Are Not Dead. My Data Says They're 10% Better.</title>
      <dc:creator>dalin zhou (钱先生)</dc:creator>
      <pubDate>Tue, 27 Oct 2026 12:45:37 +0000</pubDate>
      <link>https://dev.to/dalin_zhou_e8f17ca6/weekends-are-not-dead-my-data-says-theyre-10-better-2bnc</link>
      <guid>https://dev.to/dalin_zhou_e8f17ca6/weekends-are-not-dead-my-data-says-theyre-10-better-2bnc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F171r3fs067okryuh5j3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F171r3fs067okryuh5j3y.png" alt="Weekends are not dead: 28,230 clicks across 152 days" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every "when to post" article gives you a chart. Almost none of them explain why two charts of the same product can contradict each other.&lt;/p&gt;

&lt;p&gt;I have two of those charts. They contradict each other. That turned out to be the most useful thing I learned.&lt;/p&gt;

&lt;p&gt;This is 152 days of production data from PicKu, a URL shortener I run: &lt;strong&gt;28,230 clicks from 11,472 unique IPs, May 25 to October 23, 2026.&lt;/strong&gt; Every number below comes from my own database. Including the one where I was wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The contradiction
&lt;/h2&gt;

&lt;p&gt;An earlier analysis I published looked at the last ten days of traffic and concluded:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Weekend volume collapses to 40–60% of weekday volume."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A later analysis over 152 days concluded:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Saturday is the single biggest day of the week (4,614 clicks, 16.3%). Weekend days average about 10% more clicks than weekdays."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both came from the same database. Both were computed correctly. Only one is useful.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Day type&lt;/th&gt;
&lt;th&gt;Share of weekly clicks&lt;/th&gt;
&lt;th&gt;Per-day share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Weekdays (5 days)&lt;/td&gt;
&lt;td&gt;69.5%&lt;/td&gt;
&lt;td&gt;13.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekend (2 days)&lt;/td&gt;
&lt;td&gt;30.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you divide weekend clicks by weekday clicks you get 0.44, so "weekends get 44% of weekday volume" is arithmetically true. But that number is a &lt;strong&gt;ratio of 2 days to 5 days&lt;/strong&gt;, not a statement about demand. Per day, weekends win by about 10%.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcabk9smvdef6oltznpld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcabk9smvdef6oltznpld.png" alt="Weekend vs weekday per-day share" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I published the 44% version and it was quietly wrong in the way that matters: it told readers "don't bother on weekends," and the data says the opposite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the 10-day window lied
&lt;/h2&gt;

&lt;p&gt;The 10-day sample was October 12–21. In it, Saturday logged 97 clicks and Sunday 169, against a weekday average of 266. Clear collapse.&lt;/p&gt;

&lt;p&gt;Had I widened the window by one week, the conclusion would have flipped. Saturday is the strongest day in the full dataset, and it happened to be a weak Saturday in that particular ten-day slice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mechanism is boring and universal: weekly seasonality has a seven-day period. A window shorter than a few weeks cannot distinguish "the weekend is slow" from "that weekend was slow."&lt;/strong&gt; Two weekends is not a sample. It is an anecdote with decimals.&lt;/p&gt;

&lt;p&gt;The rule I now apply to any time-series claim, mine included: &lt;strong&gt;if the pattern has a weekly cycle, look at four or more full cycles before naming a pattern.&lt;/strong&gt; That is 28 days minimum. Anything shorter is a preview, not a finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The peak is 14:00 UTC, but 02:00 UTC is why you should care
&lt;/h2&gt;

&lt;p&gt;The busiest hour is 14:00 UTC, with 1,707 clicks (6.0%) — 2.7 times the quietest hour, 21:00, at 621 clicks (2.2%).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhubl7ocq0alfpi7kfpl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhubl7ocq0alfpi7kfpl.png" alt="Three hourly anchors" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The interesting one is second place. &lt;strong&gt;02:00 UTC posts 1,533 clicks (5.4%)&lt;/strong&gt;, clearly above its neighbours at 01:00 and 03:00. That is 9–10 PM US Eastern and 10 AM in Beijing.&lt;/p&gt;

&lt;p&gt;A single peak means one audience. A secondary peak twelve hours away means &lt;strong&gt;two audiences that never overlap&lt;/strong&gt;, and you have been optimising for the more visible one.&lt;/p&gt;

&lt;p&gt;This is an inference, not a measurement — I have not segmented clicks by region inside each hour — but the arithmetic is hard to explain any other way. The takeaway costs nothing to test: if you have a global audience and you only ever post at your local morning, you are talking to one of your two audiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it all one viral link? No.
&lt;/h2&gt;

&lt;p&gt;The objection to any timing claim from one product is survivorship: maybe one popular link was posted at a lucky hour and dragged the whole distribution with it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most-clicked single link: &lt;strong&gt;3,712 clicks, 13.1%&lt;/strong&gt; of all clicks&lt;/li&gt;
&lt;li&gt;Top five links combined: &lt;strong&gt;~30%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Remaining 801 links: &lt;strong&gt;~70%&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwofvjhk74nhfthes5tyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwofvjhk74nhfthes5tyh.png" alt="Link concentration" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No single link dominates. Timing patterns computed across 806 links are not one person's lucky afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did not do
&lt;/h2&gt;

&lt;p&gt;Three disclosures that most analytics posts skip:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;I did not filter bots.&lt;/strong&gt; The 28,230 clicks include automated traffic. With 11,472 unique IPs that is about 2.5 clicks per IP; link scanners mostly get 404s rather than recorded clicks. I believe bots are too few to reshape the hourly curve, but I cannot give you the exact ratio, so treat the curve as approximate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything is UTC.&lt;/strong&gt; Convert before acting. 14:00 UTC is 10 PM in Beijing, which is a strange time to be told to post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This is my audience, not the internet.&lt;/strong&gt; A B2B SaaS and a short-link tool have different rhythms. What travels here is the method, not the numbers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I actually changed
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Post between 12:00–14:00 UTC&lt;/strong&gt; if I can pick one slot: 8–10 AM US Eastern, 1–3 PM Central Europe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop treating Saturday as dead time.&lt;/strong&gt; In my data it is the largest single day. Weekend sharing costs nothing and it was the cheapest correction in this whole exercise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not schedule anything from a 10-day window.&lt;/strong&gt; Four full weeks or it is not a finding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Look for a second peak.&lt;/strong&gt; If your hourly curve has two humps, you have two audiences and one of them has been ignored.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The uncomfortable part is not the numbers. It is that the wrong conclusion was also mine, published, and looked completely reasonable at the time. Anyone analysing their own traffic will produce that same error, because ten days of data &lt;em&gt;is&lt;/em&gt; enough to feel confident.&lt;/p&gt;

&lt;p&gt;It is not enough to be right.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Period: 2026-05-25 to 2026-10-23. 28,230 clicks, 806 short links, 11,472 unique IPs, all times UTC. Tool: &lt;a href="https://picku.org" rel="noopener noreferrer"&gt;PicKu&lt;/a&gt;, a free URL shortener with click analytics. The full write-up, including the numbers behind every claim here, is at &lt;a href="https://picku.org/blog/when-people-actually-click" rel="noopener noreferrer"&gt;picku.org/blog/when-people-actually-click&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Part 2 of a series on short-link data. Part 1 asked what the numbers cannot tell you — half the clicks had no referrer, and 45% came from my own domains: &lt;a href="https://dev.to/dalin_zhou_e8f17ca6/27013-short-link-clicks-and-45-came-from-me-1cg4"&gt;27,013 Short-Link Clicks, and 45% Came From Me&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>webdev</category>
      <category>data</category>
      <category>productivity</category>
    </item>
    <item>
      <title>27,013 Short-Link Clicks, and 45% Came From Me</title>
      <dc:creator>dalin zhou (钱先生)</dc:creator>
      <pubDate>Tue, 27 Oct 2026 12:42:09 +0000</pubDate>
      <link>https://dev.to/dalin_zhou_e8f17ca6/27013-short-link-clicks-and-45-came-from-me-1cg4</link>
      <guid>https://dev.to/dalin_zhou_e8f17ca6/27013-short-link-clicks-and-45-came-from-me-1cg4</guid>
      <description>&lt;p&gt;Most articles about short-link analytics are invented. They show you a clean pie chart, tell you "78% of users are on mobile," you redesign your landing page around it, and nothing changes.&lt;/p&gt;

&lt;p&gt;This one is different. It is the raw output of five months of production traffic from PicKu, a URL shortener I run: &lt;strong&gt;27,013 clicks across 806 short links, from 120 countries, May 25 to October 21, 2026.&lt;/strong&gt; Every number below comes from real records, including the parts that make me look bad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd1ys25ialuqty2zo9z1m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd1ys25ialuqty2zo9z1m.png" alt="Referrer breakdown: 27,013 clicks, 45.2% self-referred, 2.6% genuinely external" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the number nobody puts in a blog post
&lt;/h2&gt;

&lt;p&gt;Of those 27,013 clicks, &lt;strong&gt;13,745 (50.9%) arrived with no referrer at all.&lt;/strong&gt; Another &lt;strong&gt;12,220 (45.2%) came from three domains I own.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Strip my own traffic out, and the genuinely external organic traffic is &lt;strong&gt;714 clicks — 2.6%&lt;/strong&gt; of the total.&lt;/p&gt;

&lt;p&gt;I could have left that out. Most write-ups would. But here is why it matters:&lt;/p&gt;

&lt;p&gt;If you read your own referrer report as "where my users come from," your promotion channels will systematically mislead you. You will conclude your users come from your other site, then spend double on that site, closing a self-congratulatory loop. I nearly did exactly that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The actionable rule: before you optimise acquisition, subtract self-referred traffic. What remains is your real acquisition surface.&lt;/strong&gt; Mine was 2.6%. Yours might be 40%. You cannot know until you subtract.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Direct" is over half. That is not a bug.
&lt;/h2&gt;

&lt;p&gt;Every short-link system shows a fat "direct" slice. This is not broken tracking — it is the fate of the format.&lt;/p&gt;

&lt;p&gt;A short link's whole job is to fit a long URL into a chat window. When someone taps it from WeChat, QQ, Slack, or email, the browser gets either no referrer or the referrer of the app's in-app container. Modern apps use their own WebViews and many strip the &lt;code&gt;Referer&lt;/code&gt; header outright as a privacy measure. You cannot intercept that.&lt;/p&gt;

&lt;p&gt;So: &lt;strong&gt;if a tool claims 100% source attribution, it is either lying or normalising only the tracked subset into something that looks clean and isn't usable.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 23% "Unknown OS" is WebViews and crawlers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OS&lt;/th&gt;
&lt;th&gt;Clicks&lt;/th&gt;
&lt;th&gt;Share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows 10&lt;/td&gt;
&lt;td&gt;9,360&lt;/td&gt;
&lt;td&gt;34.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unknown OS&lt;/td&gt;
&lt;td&gt;6,320&lt;/td&gt;
&lt;td&gt;23.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Android&lt;/td&gt;
&lt;td&gt;5,109&lt;/td&gt;
&lt;td&gt;18.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mac OS X&lt;/td&gt;
&lt;td&gt;2,800&lt;/td&gt;
&lt;td&gt;10.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iPhone&lt;/td&gt;
&lt;td&gt;2,424&lt;/td&gt;
&lt;td&gt;9.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;645&lt;/td&gt;
&lt;td&gt;2.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;iPad&lt;/td&gt;
&lt;td&gt;125&lt;/td&gt;
&lt;td&gt;0.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 7&lt;/td&gt;
&lt;td&gt;91&lt;/td&gt;
&lt;td&gt;0.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;My first reaction to "Unknown OS" at second place was that my parser was broken. It isn't. Three things land in that bucket:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;App WebViews that omit key fields or disguise themselves&lt;/li&gt;
&lt;li&gt;In-app browsers (27.8% of all traffic, see next section)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search engine prefetching&lt;/strong&gt; — Baidu, 360, and Bing crawlers hit short links constantly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That third one deserves emphasis: &lt;strong&gt;short-link pages are among the most heavily crawled page types on the web.&lt;/strong&gt; Any public short link shared into a group chat gets crawled within hours. Counting those as analytics is measuring bot traffic.&lt;/p&gt;

&lt;p&gt;At least half of that 23% is WebView plus crawlers. That is why "mobile share" is such a soft number across most short-link tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One conclusion does survive the noise:&lt;/strong&gt; Windows 10 at 34.7% plus Windows 7 at 91 clicks makes desktop Windows the absolute majority. If your short links point at landing pages with images, popups, or splash screens, design for 1366×768 through 1920×1080 &lt;strong&gt;first&lt;/strong&gt;, mobile second. That runs against instinct. The data decides it, not instinct.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Handheld Browser" at 27.8% is not a browser
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Browser&lt;/th&gt;
&lt;th&gt;Clicks&lt;/th&gt;
&lt;th&gt;Share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chrome&lt;/td&gt;
&lt;td&gt;12,632&lt;/td&gt;
&lt;td&gt;46.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Handheld Browser&lt;/td&gt;
&lt;td&gt;7,520&lt;/td&gt;
&lt;td&gt;27.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unknown Browser&lt;/td&gt;
&lt;td&gt;5,359&lt;/td&gt;
&lt;td&gt;19.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firefox&lt;/td&gt;
&lt;td&gt;790&lt;/td&gt;
&lt;td&gt;2.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Safari&lt;/td&gt;
&lt;td&gt;695&lt;/td&gt;
&lt;td&gt;2.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;0.02%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opera&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;"Handheld Browser" is the fallback label a server-side UA parser assigns when it cannot identify the engine &lt;strong&gt;at all&lt;/strong&gt;. Everything in that bucket is, in substance, a mobile WebView. The frequency check confirms it: Opera, a genuinely obscure desktop browser, managed exactly 1 click.&lt;/p&gt;

&lt;p&gt;For anyone shipping a landing page, this matters far more than "Chrome is 46.8%":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WeChat's in-app browser doesn't support all modern CSS&lt;/strong&gt; — &lt;code&gt;backdrop-filter&lt;/code&gt;, &lt;code&gt;:has()&lt;/code&gt;, and some &lt;code&gt;position: sticky&lt;/code&gt; behaviour&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WeChat intercepts pages with outbound links&lt;/strong&gt;, so an outbound button may render as an interstitial&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebP support depends on the WeChat version&lt;/strong&gt; — older WebViews show a blank block where your carefully optimised image should be&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run short links in China, open your splash page &lt;strong&gt;inside WeChat itself&lt;/strong&gt;, not in Chrome's device emulator. I have seen too many pages that "looked fine in the emulator" and showed no image in WeChat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moldova is not your 12th biggest market
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Country&lt;/th&gt;
&lt;th&gt;Clicks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;China&lt;/td&gt;
&lt;td&gt;10,127&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;United States&lt;/td&gt;
&lt;td&gt;6,174&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;France&lt;/td&gt;
&lt;td&gt;1,722&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;(blank)&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;1,417&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Japan&lt;/td&gt;
&lt;td&gt;1,268&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;United Kingdom&lt;/td&gt;
&lt;td&gt;875&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Germany&lt;/td&gt;
&lt;td&gt;609&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hong Kong, China&lt;/td&gt;
&lt;td&gt;441&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canada&lt;/td&gt;
&lt;td&gt;420&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Taiwan, China&lt;/td&gt;
&lt;td&gt;399&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;South Africa&lt;/td&gt;
&lt;td&gt;388&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Republic of Moldova&lt;/td&gt;
&lt;td&gt;385&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That blank 1,417 (5.2%) is not "unknown country" — it means the request carried no resolvable IP. Causes: server-side internal redirects, proxy requests, CDN origin fetches, crawlers.&lt;/p&gt;

&lt;p&gt;The easy misreading: see "China 10,127, US 6,174" and conclude your users split evenly between China and the US. But with 13,745 direct clicks in the referrer column, there is no way to tell how many were Chinese users clicking Chinese links versus overseas users clicking Chinese links.&lt;/p&gt;

&lt;p&gt;The telling outlier is &lt;strong&gt;Republic of Moldova at 385 clicks, rank 12.&lt;/strong&gt; Moldova has about 2.5 million people. A country of 2.5 million contributing 1.4% of all clicks — ahead of Japan, the UK, and Germany per-capita by an absurd margin — is not a normal number. My read: those are overseas VPS or proxy egress IPs that geolocate to Moldova, or imprecise IP database data for the region. Moldova is a known proxy-relay hub in Europe.&lt;/p&gt;

&lt;p&gt;The lesson is not "localise for Moldova." It is: &lt;strong&gt;always distrust the outliers in the long tail.&lt;/strong&gt; When a country suddenly enters your top five, check IP attribution before you build a campaign for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 207-a-day average hides a weekly rhythm
&lt;/h2&gt;

&lt;p&gt;October 12–21 totals 2,068 clicks, a daily average of 206.8.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Day&lt;/th&gt;
&lt;th&gt;Clicks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Weekdays (avg)&lt;/td&gt;
&lt;td&gt;266&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sat, Oct 12&lt;/td&gt;
&lt;td&gt;97&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sun, Oct 13&lt;/td&gt;
&lt;td&gt;169&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Weekend volume collapses to &lt;strong&gt;40–60% of weekday volume&lt;/strong&gt;, and the pattern is very stable.&lt;/p&gt;

&lt;p&gt;That is directly usable for scheduling: &lt;strong&gt;weekday daytime is the main arena&lt;/strong&gt; — that is when load time and reliability matter most.&lt;/p&gt;

&lt;p&gt;One caution I nearly got wrong myself: Oct 13's 169 looks like a drop, but it is a Sunday. &lt;strong&gt;Never judge a trend from a single day.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What this data is actually for
&lt;/h2&gt;

&lt;p&gt;If you read those five tables and thought "so what," here are the three things I actually do with them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Decide landing page dimensions instead of guessing.&lt;/strong&gt;&lt;br&gt;
Desktop Windows at 34.7% means design for 1440px wide, then fold down for mobile. Not the reverse. Most people get this order backwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Decide what your stack must support.&lt;/strong&gt;&lt;br&gt;
Handheld Browser at 27.8% means old WebView compatibility is mandatory: no &lt;code&gt;:has()&lt;/code&gt;, do not lean on &lt;code&gt;backdrop-filter&lt;/code&gt;, ship both WebP and JPG.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Strip self-owned traffic before deciding where to spend.&lt;/strong&gt;&lt;br&gt;
Remove my own domains and external natural traffic is 2.6%. That number is small, but it tells me something more important than any acquisition report: &lt;strong&gt;I currently have almost no external acquisition.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;50.9% of clicks had no referrer. Normal, not broken.&lt;/li&gt;
&lt;li&gt;45.2% came from my own domains. That is the number that should worry you about your own data.&lt;/li&gt;
&lt;li&gt;2.6% was genuinely external. That is the number that should drive your budget.&lt;/li&gt;
&lt;li&gt;"Unknown OS" and "Handheld Browser" are not user segments. They are measurement failure.&lt;/li&gt;
&lt;li&gt;A country ranking can be a proxy artefact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your analytics show a clean picture, you are probably looking at a filtered report.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Raw dataset: 27,013 clicks, 806 links, 27,002 detail rows (an 11-row gap, 0.04%, is crawler traffic that redirects but carries no referrer or complete UA). 120 countries. Period: 2026-05-25 to 2026-10-21. Tool: &lt;a href="https://picku.org" rel="noopener noreferrer"&gt;PicKu&lt;/a&gt; — free URL shortener with click analytics. The full breakdown, including the numbers I left in this post, is at &lt;a href="https://picku.org/blog/short-link-analytics-blind-spots" rel="noopener noreferrer"&gt;picku.org/blog/short-link-analytics-blind-spots&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Part 1 of a series. Part 2 takes the part the data does have — timing — and finds something I got wrong the first time: weekends are not dead, Saturday is the biggest day of the week. &lt;a href="https://dev.to/dalin_zhou_e8f17ca6/weekends-are-not-dead-my-data-says-theyre-10-better-2bnc"&gt;Weekends Are Not Dead. My Data Says They're 10% Better.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>webdev</category>
      <category>data</category>
      <category>performance</category>
    </item>
    <item>
      <title>How I Built a URL Shortener with Click Analytics (Architecture Deep Dive)</title>
      <dc:creator>dalin zhou (钱先生)</dc:creator>
      <pubDate>Fri, 09 Oct 2026 12:35:47 +0000</pubDate>
      <link>https://dev.to/dalin_zhou_e8f17ca6/how-i-built-a-url-shortener-with-click-analytics-architecture-deep-dive-4ini</link>
      <guid>https://dev.to/dalin_zhou_e8f17ca6/how-i-built-a-url-shortener-with-click-analytics-architecture-deep-dive-4ini</guid>
      <description>&lt;p&gt;Most URL shorteners solve the "make it short" problem and stop there. When I set out&lt;br&gt;
to build PicKu, I wanted to answer a different question: what actually happens&lt;br&gt;
&lt;em&gt;after&lt;/em&gt; someone clicks your short link?&lt;/p&gt;

&lt;p&gt;This is a write-up of the architecture decisions behind PicKu — including the ones&lt;br&gt;
that turned out to be harder than expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obvious requirements
&lt;/h2&gt;

&lt;p&gt;A URL shortener needs three things to work at all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast alias lookup&lt;/strong&gt; — resolve &lt;code&gt;picku.org/aBcD&lt;/code&gt; to a destination URL in single-digit milliseconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe redirects&lt;/strong&gt; — open redirect is the #1 abuse vector for any shortener&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Click counting&lt;/strong&gt; — the reason most people actually use one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the easy part. The interesting parts were everything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Redis for alias resolution
&lt;/h2&gt;

&lt;p&gt;The lookup path is read-heavy and latency-sensitive: every click is a read, and&lt;br&gt;
short links are hit in bursts. A link gets shared, a Slack channel reacts, traffic&lt;br&gt;
spikes for ten minutes, then it dies.&lt;/p&gt;

&lt;p&gt;A relational database handles this fine — until it doesn't. Sibling rows land on the&lt;br&gt;
same physical page, and a viral link turns into a hot-page contention problem.&lt;/p&gt;

&lt;p&gt;Redis key-value lookups are O(1) with no page contention, which is exactly the shape&lt;br&gt;
of this workload. The tradeoff is durability: Redis alone loses data on restart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pattern I settled on&lt;/strong&gt;: Redis as the read path, with write-through to the&lt;br&gt;
primary store on every create. Reads are fast and cheap; the source of truth is still&lt;br&gt;
durable. If Redis comes back empty after a restart, it rebuilds from the durable store.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Link expiry without a cron army
&lt;/h2&gt;

&lt;p&gt;Expiring links sounds like it needs a scheduled job scanning every link every minute.&lt;br&gt;
That approach falls over quickly — a million links means a million-row scan every&lt;br&gt;
minute, and most of those links are nowhere near expiry.&lt;/p&gt;

&lt;p&gt;Instead: &lt;strong&gt;lazy expiry&lt;/strong&gt;. Store &lt;code&gt;expires_at&lt;/code&gt; with each link. On every lookup, check it:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
python
if link.expires_at and link.expires_at &amp;lt; now:
    mark_expired(link)
    return 410, "Gone"
return redirect(link.destination)
Zero background cost. Expired links cost one timestamp comparison, and you only pay
it on links actually being clicked — which, for most expired links, is never.
If you're building this yourself: decide your abuse policy before you write the
redirect handler. Retrofitting it means rewriting the hot path.
3. The abuse problem is the real hard part
Any URL shortener becomes an open redirect service the moment someone posts a
malicious link to a forum. Two things handle it:
Domain allowlisting for custom aliases. Custom aliases are opt-in, and the set of
destinations that may use them is controlled. This is the single biggest abuse
reduction lever.
Reputation scoring, not keyword blocking. Every destination domain accumulates a
score based on reports, age, and traffic patterns. Below a threshold, links are held
for review instead of served immediately.
The reason not to go keyword-filter-first: attackers trivially evade keyword filters,
and legitimate short links get caught constantly. Score the destination, not the string.
4. Analytics: what people actually want to see
The raw click count is the least interesting number. What people pay for is where the
click came from:
- Referrer — the referring URL, not just "direct"
- Country — resolved at click time, not at redirect time
- Device / browser — parsed from the user agent
- Timestamp — with a sane retention window, not forever
Two design notes that mattered:
Resolve geo at click time, not at creation time. A link created in one country
often gets clicked in another. Resolving at redirect is both cheaper and correct.
Retention beats resolution here. Analytics that keep three years of per-click rows
are expensive and nobody reads them that far back. A tight window (90 days on the free
tier, longer for paid) is the better trade.
5. Custom splash and overlay pages
Sometimes you don't want an instant redirect — you want a page with your branding, a
countdown, or a click-through. This is what the Direct Frame vs Splash options in the
UI control:
- Direct frame → straight redirect, zero friction
- Splash → branded intermediate page, optional countdown
- Custom domain → your own domain stays in the address bar, which matters for
brand trust and for link-preview screenshots in social apps
Custom domains are also what make a short link survive being shared in a room full of
people who don't trust bit.ly.
What I'd do differently
If I rebuilt this, I'd spend two more weeks on rate limiting and bot detection
before launch rather than after. Every shortener attracts scrapers within days of
launching — they're scanning for open redirects. Building it in from the start is
cheaper than retrofitting it under load.
The other thing I'd do earlier: make the API first-class from day one. A lot of
the long-term value came from integrations, not from the web UI.
If you're interested in comparing implementations or have questions about any of the
above, I'm happy to go deeper in the comments.
For reference, the tool this post is based on is here: https://picku.org — free tier
covers 10 links, and the paid tier removes ads and unlocks unlimited links, custom
domains, and API access.
Questions about any part of this? Happy to go deeper.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>webdev</category>
      <category>redis</category>
      <category>architecture</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
