<?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: Derrick Zhou</title>
    <description>The latest articles on DEV Community by Derrick Zhou (@derrick_d15159abe0a5e6608).</description>
    <link>https://dev.to/derrick_d15159abe0a5e6608</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%2F4109008%2Ffe1e4ac3-dc08-4c7a-b067-e49a7d4d09be.png</url>
      <title>DEV Community: Derrick Zhou</title>
      <link>https://dev.to/derrick_d15159abe0a5e6608</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/derrick_d15159abe0a5e6608"/>
    <language>en</language>
    <item>
      <title>Measuring China's Company Registry from the Outside: A Technical Writeup</title>
      <dc:creator>Derrick Zhou</dc:creator>
      <pubDate>Mon, 07 Sep 2026 05:55:09 +0000</pubDate>
      <link>https://dev.to/derrick_d15159abe0a5e6608/measuring-chinas-company-registry-from-the-outside-a-technical-writeup-2kh8</link>
      <guid>https://dev.to/derrick_d15159abe0a5e6608/measuring-chinas-company-registry-from-the-outside-a-technical-writeup-2kh8</guid>
      <description>&lt;p&gt;&lt;em&gt;How we designed paired-control experiments to measure government registry accessibility — and what the data shows.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you've ever built a tool that queries a government database, you know the pain: no API, no docs, no SLA. Now imagine that database is China's national company registry, serves 160 million business records, and actively distinguishes between human browsers and everything else.&lt;/p&gt;

&lt;p&gt;We run &lt;a href="https://currawongweb.com" rel="noopener noreferrer"&gt;Currawong Web&lt;/a&gt;, a supplier verification service. Over the past few months we ran controlled experiments measuring what happens when you try to access Chinese government registries from outside China. We published 20 datasets on &lt;a href="https://dataverse.harvard.edu/" rel="noopener noreferrer"&gt;Harvard Dataverse&lt;/a&gt; — all CC-licensed, all reproducible. Here's the technical story.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: a registry that fights back
&lt;/h2&gt;

&lt;p&gt;China's national company registry (国家企业信用信息公示系统, or NECIPS) holds the canonical registration data for every company in the country. It's the source of truth for business licence details, legal representative, registered capital, and operational status.&lt;/p&gt;

&lt;p&gt;It also serves a JavaScript challenge to every visitor.&lt;/p&gt;

&lt;p&gt;This isn't a simple cookie check. The challenge evaluates your client environment — we observed different outcomes depending on browser fingerprint characteristics even from the same IP address. The system appears to use these signals to decide whether to serve data or return an empty response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment design
&lt;/h2&gt;

&lt;p&gt;We wanted to measure this systematically, not just anecdote our way through it. So we designed a paired-control experiment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Variables:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client profile matrix&lt;/strong&gt;: 5 distinct browser fingerprint configurations, ranging from a vanilla Chrome profile to headless configurations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entry point matrix&lt;/strong&gt;: direct URL, search-engine referral, and portal navigation paths&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network location&lt;/strong&gt;: 2 mainland China networks + 1 overseas comparison point&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Protocol:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 rounds per combination&lt;/li&gt;
&lt;li&gt;Same target company in each round&lt;/li&gt;
&lt;li&gt;Record: HTTP status, JS challenge presence, data payload presence, time to response&lt;/li&gt;
&lt;li&gt;Control: a known-accessible domestic business portal queried in the same session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gave us a structured matrix of observations rather than a single pass/fail answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the JS challenge actually does
&lt;/h2&gt;

&lt;p&gt;We're deliberately not publishing bypass methods — that would undermine a legitimate anti-scraping system. But the technical observation is worth documenting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initial page load&lt;/strong&gt; returns a minimal HTML shell with an inline script&lt;/li&gt;
&lt;li&gt;The script performs &lt;strong&gt;environment checks&lt;/strong&gt; — we observed it probing properties that differ between headless and headed browsers&lt;/li&gt;
&lt;li&gt;On passing, a &lt;strong&gt;cookie is set&lt;/strong&gt; and the page reloads with actual content&lt;/li&gt;
&lt;li&gt;On failing, the page either loops or returns empty content — no error message, no HTTP error code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The subtlety is that this isn't binary. Some client profiles pass the challenge but receive degraded results. The registry appears to have multiple tiers of trust, not just allow/block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results: what works and what doesn't
&lt;/h2&gt;

&lt;p&gt;From our 106-company English-name lookup dataset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end success rate was low.&lt;/strong&gt; Most failures occurred before the verification step — at the name-matching stage, not the access stage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network location matters&lt;/strong&gt;, but less than client profile. A well-configured browser from overseas performed better than a poorly configured one from inside China.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certificate registries vary wildly.&lt;/strong&gt; We tested 8 official sources (CCC, CQC, CFDA, and others) with 240 observations. Some answer reliably from any location. Others are effectively unreachable without a China-side session.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The registration-change problem
&lt;/h2&gt;

&lt;p&gt;One dataset tracked 264 manufacturers classified as national "Little Giant" firms (专精特新"小巨人"). We compared registration snapshots over time and found that key fields — operational status, registered capital, business scope — shift more frequently than most due-diligence processes assume.&lt;/p&gt;

&lt;p&gt;A supplier check from 6 months ago may already be outdated. This isn't a data-quality issue — it's a feature of a dynamic registry system that reflects real corporate changes. The implication for anyone building verification tooling is that you need a freshness model, not a cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alibaba vs. 1688: identity field comparison
&lt;/h2&gt;

&lt;p&gt;We also compared supplier identity fields between Alibaba.com (international) and 1688.com (domestic) for 94 companies present on both platforms. The registered company names, addresses, and representative details don't always match — not because of fraud, but because of legitimate differences in how companies present themselves for international vs. domestic trade.&lt;/p&gt;

&lt;p&gt;This matters for entity resolution. If your verification system tries to match a supplier's Alibaba profile against the government registry using the English trade name, you'll get a different result than matching via the Chinese registered name on 1688.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons for builders
&lt;/h2&gt;

&lt;p&gt;If you're building tools that interact with government data sources — in any country — a few patterns from this work apply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measure access, don't assume it.&lt;/strong&gt; We started with the assumption that the registry was accessible. The data showed a more nuanced picture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for failure tiers&lt;/strong&gt;, not binary up/down. A system that returns empty content with HTTP 200 is harder to handle than one that returns 403.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client fingerprint matters more than you think.&lt;/strong&gt; We saw different outcomes from the same network with different browser configurations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a freshness model.&lt;/strong&gt; Government records change. Your verification is a snapshot, not a permanent fact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate name-matching from access.&lt;/strong&gt; Our biggest source of failure wasn't "can't reach the registry" — it was "can't find the company by its English name."&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Data availability
&lt;/h2&gt;

&lt;p&gt;All 20 datasets are on Harvard Dataverse with DOIs and CC licences. Download them, reproduce the experiments, challenge the methodology. That's the point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dataverse.harvard.edu/" rel="noopener noreferrer"&gt;Currawong Web research datasets on Harvard Dataverse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://currawongweb.com" rel="noopener noreferrer"&gt;currawongweb.com&lt;/a&gt; — our supplier verification service&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Derrick Zhou builds supplier verification tools at Currawong Web. Previously worked in cross-border trade operations.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>data</category>
      <category>security</category>
    </item>
    <item>
      <title>How China's company registration code uses ISO 7064 check digits (and why it matters for importers)</title>
      <dc:creator>Derrick Zhou</dc:creator>
      <pubDate>Fri, 04 Sep 2026 04:31:33 +0000</pubDate>
      <link>https://dev.to/derrick_d15159abe0a5e6608/how-chinas-company-registration-code-uses-iso-7064-check-digits-and-why-it-matters-for-importers-1312</link>
      <guid>https://dev.to/derrick_d15159abe0a5e6608/how-chinas-company-registration-code-uses-iso-7064-check-digits-and-why-it-matters-for-importers-1312</guid>
      <description>&lt;p&gt;If you've ever sourced products from China, you've probably seen an 18-character code on your supplier's business licence. It looks something like this:&lt;/p&gt;

&lt;p&gt;91440300MA5FJK2W30&lt;/p&gt;

&lt;p&gt;This is the Unified Social Credit Identifier (USCI) — China's equivalent of a company registration number. And buried in its last character is a check digit based on ISO 7064 Mod 31-3.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the code tells you
&lt;/h2&gt;

&lt;p&gt;The 18 characters encode specific information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Position 1: Registration authority type&lt;/li&gt;
&lt;li&gt;Position 2: Organization category&lt;/li&gt;
&lt;li&gt;Positions 3-9: Regional code (maps to province/city/district)&lt;/li&gt;
&lt;li&gt;Positions 10-17: Organization identifier&lt;/li&gt;
&lt;li&gt;Position 18: Check digit (ISO 7064 Mod 31-3)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The check digit math
&lt;/h2&gt;

&lt;p&gt;The validation uses a weighted sum mod 31, with weights cycling through powers of 3. Here's a JavaScript implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateUSCI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0123456789ABCDEFGHJKLMNPQRTUWXY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;remainder&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: USCI uses a custom character set — no I, O, S, V, Z (to avoid visual confusion with 1, 0, 5, U, 2).&lt;/p&gt;

&lt;h2&gt;
  
  
  How well does it work?
&lt;/h2&gt;

&lt;p&gt;I ran an exhaustive test: for every position in every sample code, I substituted every possible character and checked whether the check digit caught the error.&lt;/p&gt;

&lt;p&gt;Result: 100% detection of single-character substitutions across 2.9 million simulated errors.&lt;/p&gt;

&lt;p&gt;For comparison, the US VIN (Vehicle Identification Number) check digit only catches 92.5% of single-character errors.&lt;/p&gt;

&lt;p&gt;The full dataset is on Zenodo: &lt;a href="https://zenodo.org/records/15589531" rel="noopener noreferrer"&gt;https://zenodo.org/records/15589531&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;If a supplier sends you a business licence with a typo in the registration code — or a completely fabricated code — the check digit catches it instantly, before you spend time on a manual lookup.&lt;/p&gt;

&lt;p&gt;Some other findings from our research:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;42.5% of NHTSA-registered Chinese manufacturers can't be found by English name alone in China's registry&lt;/li&gt;
&lt;li&gt;25.4% of China's "little giant" manufacturers don't have import/export in their registered business scope&lt;/li&gt;
&lt;li&gt;53.4% of those manufacturers have changed their company name at least once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built a free tool that does this validation plus a manual cross-reference against official Chinese registry data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://currawongweb.com/verify/" rel="noopener noreferrer"&gt;https://currawongweb.com/verify/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The research papers and datasets are all open access. Happy to answer questions about the methodology.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>data</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
