<?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: galb</title>
    <description>The latest articles on DEV Community by galb (@galbe).</description>
    <link>https://dev.to/galbe</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%2F4199744%2Ffa9881c4-63cb-4768-bbc7-b788fc857b0f.png</url>
      <title>DEV Community: galb</title>
      <link>https://dev.to/galbe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/galbe"/>
    <language>en</language>
    <item>
      <title>How to see Vercel Web Analytics for all your projects at once</title>
      <dc:creator>galb</dc:creator>
      <pubDate>Sun, 25 Oct 2026 14:30:54 +0000</pubDate>
      <link>https://dev.to/galbe/how-to-see-vercel-web-analytics-for-all-your-projects-at-once-him</link>
      <guid>https://dev.to/galbe/how-to-see-vercel-web-analytics-for-all-your-projects-at-once-him</guid>
      <description>&lt;p&gt;If you have more than a few projects on Vercel, you know the routine: open a project, click Analytics, note the numbers, go back, open the next one. Vercel shows Web Analytics one project at a time.&lt;/p&gt;

&lt;p&gt;In May 2026 Vercel made its &lt;a href="https://vercel.com/changelog/web-analytics-api" rel="noopener noreferrer"&gt;Web Analytics API public&lt;/a&gt;. This post shows how to use it to get the numbers for every project, and what you have to build around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API in two minutes
&lt;/h2&gt;

&lt;p&gt;There are two datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visits&lt;/strong&gt;: page views tracked automatically, with &lt;code&gt;pageviews&lt;/code&gt; and &lt;code&gt;visitors&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt;: custom events sent with &lt;code&gt;track()&lt;/code&gt;, with &lt;code&gt;count&lt;/code&gt; and &lt;code&gt;visitors&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each dataset has two queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Count&lt;/strong&gt; (&lt;code&gt;/v1/query/web-analytics/visits/count&lt;/code&gt;) returns one total.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggregate&lt;/strong&gt; (&lt;code&gt;/v1/query/web-analytics/visits/aggregate&lt;/code&gt;) returns rows grouped by up to two dimensions in &lt;code&gt;by&lt;/code&gt;. One can be a time unit (&lt;code&gt;hour&lt;/code&gt;, &lt;code&gt;day&lt;/code&gt;, &lt;code&gt;week&lt;/code&gt;, &lt;code&gt;month&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt;). The others include &lt;code&gt;country&lt;/code&gt;, &lt;code&gt;referrerHostname&lt;/code&gt;, &lt;code&gt;requestPath&lt;/code&gt;, &lt;code&gt;deviceType&lt;/code&gt;, &lt;code&gt;browserName&lt;/code&gt; and the UTM fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You authenticate with a normal Vercel access token. You pass a &lt;code&gt;projectId&lt;/code&gt;, plus &lt;code&gt;teamId&lt;/code&gt; for team projects.&lt;/p&gt;

&lt;p&gt;Visitors and page views for one project over a week:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--get&lt;/span&gt; &lt;span class="s2"&gt;"https://api.vercel.com/v1/query/web-analytics/visits/count"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$VERCEL_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"teamId=team_1234567890"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"projectId=prj_1234567890"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"since=2026-10-05"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"until=2026-10-11"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a chart, ask the aggregate endpoint for one row per day:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--get&lt;/span&gt; &lt;span class="s2"&gt;"https://api.vercel.com/v1/query/web-analytics/visits/aggregate"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$VERCEL_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"teamId=team_1234567890"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"projectId=prj_1234567890"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"since=2026-10-05"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"until=2026-10-11"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s2"&gt;"by=day"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The catch: one project per request
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;projectId&lt;/code&gt; is required on every query. To see all your projects, you build the rest yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;List the projects.&lt;/strong&gt; Call the projects API for each team, page through the results, and skip projects without Web Analytics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make several queries per project.&lt;/strong&gt; Totals, a daily series, top referrers and top countries are separate calls. At five calls per project, 100 projects cost about 500 calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query the previous period too.&lt;/strong&gt; "Up 12% on last week" needs the same queries again for the week before. That period must be inside your plan's reporting window: 1 month on Hobby, 12 months on Pro, 24 months with Web Analytics Plus or Enterprise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Respect rate limits.&lt;/strong&gt; The docs don't state a limit. In our tests, responses carried &lt;code&gt;x-ratelimit-limit: 400&lt;/code&gt; with a reset about a minute later. A large team needs a queue, backoff on 429, and a cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mind time zones.&lt;/strong&gt; In our tests, time buckets were in UTC and the API had no time zone parameter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep one token per team.&lt;/strong&gt; A team-scoped token sees one team, so agencies keep several. In our tests, personal access tokens worked, but integration tokens got 404 from the Web Analytics endpoints.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  For a one-off answer: the CLI
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;vercel metrics&lt;/code&gt; queries the same data from a terminal. With &lt;code&gt;--all&lt;/code&gt; and &lt;code&gt;--group-by projectId&lt;/code&gt; it covers every project in the current team. It's a good fit for a question you ask once. It isn't a dashboard someone else can open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Or use Lookout
&lt;/h2&gt;

&lt;p&gt;I hit this problem with my own projects, so I built &lt;a href="https://lookoutstats.com" rel="noopener noreferrer"&gt;Lookout&lt;/a&gt;. It's the script above, finished:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every project's visitors, page views and pages per visit on one board, against the previous period&lt;/li&gt;
&lt;li&gt;Compare up to five projects on one chart&lt;/li&gt;
&lt;li&gt;A read-only share link per board for clients, with no Vercel seat&lt;/li&gt;
&lt;li&gt;Email alerts when a site spikes or drops, and a TV mode&lt;/li&gt;
&lt;li&gt;An open-source MCP server, &lt;a href="https://github.com/lookoutstats/lookout-mcp" rel="noopener noreferrer"&gt;lookout-mcp&lt;/a&gt;, so Claude or Cursor can answer "which of my sites grew this week?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You paste a Vercel token scoped the way you choose, and Lookout caches results and handles the rate limits. There's a &lt;a href="https://lookoutstats.com/demo" rel="noopener noreferrer"&gt;live demo&lt;/a&gt; that needs no sign-up.&lt;/p&gt;

&lt;p&gt;Whichever way you go, I'd like to hear how you track several Vercel projects today. Leave a comment.&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>nextjs</category>
      <category>analytics</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Agents misread Hebrew. A 40-year-old aerospace standard helps.</title>
      <dc:creator>galb</dc:creator>
      <pubDate>Thu, 22 Oct 2026 07:04:16 +0000</pubDate>
      <link>https://dev.to/galbe/agents-misread-hebrew-a-40-year-old-aerospace-standard-helps-370</link>
      <guid>https://dev.to/galbe/agents-misread-hebrew-a-40-year-old-aerospace-standard-helps-370</guid>
      <description>&lt;p&gt;In aerospace maintenance, a misread instruction can ground an aircraft, or cause worse damage. So the industry built ASD-STE100, Simplified Technical English. It is a controlled language with one meaning per word, active voice, short sentences, and one instruction per sentence.&lt;/p&gt;

&lt;p&gt;Today a new kind of reader parses technical text with no one to ask: the AI agent. A model reads tool descriptions, error messages, and instructions between agents. It cannot ask the author what the author meant. &lt;a href="https://github.com/danyuchn/asd-ste100-skill" rel="noopener noreferrer"&gt;danyuchn/asd-ste100-skill&lt;/a&gt; applies STE100 to English agent text as a Claude Code skill. I ported it to Hebrew.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Hebrew needs its own rules
&lt;/h2&gt;

&lt;p&gt;STE100 defines English only. No official Hebrew version exists, so every Hebrew rule here is an adaptation. Some English rules carry over directly. Others have no English equivalent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep &lt;code&gt;את&lt;/code&gt;.&lt;/strong&gt; Headline-style Hebrew drops &lt;code&gt;את&lt;/code&gt; before a definite object: "למחוק קובץ ההגדרות". Keep it: "למחוק את קובץ ההגדרות". Then the direct object is explicit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put a hyphen before Latin text and digits.&lt;/strong&gt; In "בשרת הAPI", the prefix merges into the term. Write "בשרת ה-API".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use one instruction form.&lt;/strong&gt; Hebrew procedures often mix the imperative ("פתח"), "יש ל-", and the future tense ("תבדוק"). The skill uses the infinitive ("לפתוח") for every instruction. The infinitive is also gender-neutral.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use one part of speech per word.&lt;/strong&gt; In "המשתמש משתמש בכלי", &lt;code&gt;משתמש&lt;/code&gt; is both "user" and "uses". Keep it a noun and use a different verb: "המשתמש מפעיל את הכלי".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not use &lt;code&gt;לבצע&lt;/code&gt; with an action noun.&lt;/strong&gt; "לבצע בדיקה של המסנן" hides the action in a noun. Write "לבדוק את המסנן".&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The most important rule: hedges stay hedges
&lt;/h2&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ייתכן שאירעה שגיאה במהלך עיבוד הבקשה שלך עקב אי-התאמה אפשרית בפורמט הנתונים הצפוי, אשר עשויה להיגרם כתוצאה מגרסת לקוח שאינה מעודכנת.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ייתכן שאירעה שגיאה בעיבוד הבקשה. ייתכן שהסיבה היא אי-התאמה בפורמט הנתונים הצפוי. ייתכן שגרסת לקוח לא מעודכנת גרמה לאי-ההתאמה הזו.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"אירעה שגיאה" ("an error occurred") reads better. But it states an error that the system only suspects. A simplifier that removes uncertainty makes the text clearer and wrong. The skill splits the sentence into three claims and keeps every hedge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two modes and a linter
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strict mode&lt;/strong&gt; is for procedures, error messages, tool descriptions, and agent instructions. It applies every rule, including the length limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flavored mode&lt;/strong&gt; is for README prose. It removes marketing words that have no measurement, and it keeps every claim.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A Python linter (&lt;code&gt;scripts/ste-lint-he.py&lt;/code&gt;) uses only the standard library. It does a mechanical first pass: semicolons, sentence length, nominalization, marketing words, prefix hyphens, slang, and synonym rotation. It cannot check construct chains, homographs, or a dropped &lt;code&gt;את&lt;/code&gt;. The model and the author check those.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add g4lb/asd-ste100-hebrew-skill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ask Claude: &lt;code&gt;פשט את תיאור הכלי הזה&lt;/code&gt; ("simplify this tool description").&lt;/p&gt;

&lt;p&gt;Repository (MIT license): &lt;a href="https://github.com/g4lb/asd-ste100-hebrew-skill" rel="noopener noreferrer"&gt;https://github.com/g4lb/asd-ste100-hebrew-skill&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you write Hebrew for agents, tell me which rules feel wrong.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>hebrew</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
