<?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: Muhammad Afzal</title>
    <description>The latest articles on DEV Community by Muhammad Afzal (@mafzal9).</description>
    <link>https://dev.to/mafzal9</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%2F826909%2F2ff0dd58-67e1-4046-b262-6a1fcb81d9b3.jpeg</url>
      <title>DEV Community: Muhammad Afzal</title>
      <link>https://dev.to/mafzal9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mafzal9"/>
    <language>en</language>
    <item>
      <title>Package Tracking API for UPS, FedEx &amp; DHL: No Carrier Keys</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Thu, 05 Nov 2026 03:30:48 +0000</pubDate>
      <link>https://dev.to/mafzal9/package-tracking-api-for-ups-fedex-dhl-no-carrier-keys-437i</link>
      <guid>https://dev.to/mafzal9/package-tracking-api-for-ups-fedex-dhl-no-carrier-keys-437i</guid>
      <description>&lt;p&gt;You can get a package tracking API for UPS, FedEx, DHL and many postal services without registering for three carrier developer programs: send batches of tracking numbers to five pay-per-result tracking Actors on Apify through one client library, and get one JSON record per package with its status, delivery estimate and latest scan. On Apify's FREE plan it costs USD 20 per 1,000 FedEx or DHL records, USD 30 per 1,000 UPS records and USD 39 per 1,000 records for other carriers, and numbers that return nothing are not charged.&lt;/p&gt;

&lt;p&gt;This post builds a small script that reads a CSV of mixed tracking numbers, routes each one to the right tracker, and writes a single &lt;code&gt;tracking-status.csv&lt;/code&gt;. Then it shows how to connect the same trackers to an AI agent in Claude, ChatGPT, Codex, Gemini, Grok or Cursor through Apify's MCP server, with automation recipes you can copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I built and maintain the five Actors used here, and they are paid tools on Apify Store. I've kept to batch sizes, field names and prices you can check on each Store page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which tracker handles which carrier?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Carrier&lt;/th&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;Numbers per run&lt;/th&gt;
&lt;th&gt;Scan history&lt;/th&gt;
&lt;th&gt;FREE price per 1,000 records&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FedEx (tracking and door-tag numbers)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://apify.com/muhammadafzal/fedex-package-tracking-scraper" rel="noopener noreferrer"&gt;FedEx Tracking Scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;USD 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UPS (tracking and InfoNotice numbers)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://apify.com/muhammadafzal/ups-package-tracking-scraper" rel="noopener noreferrer"&gt;UPS Tracking Scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;Latest update only&lt;/td&gt;
&lt;td&gt;USD 30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DHL (Express, eCommerce, supply chain)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://apify.com/muhammadafzal/dhl-package-tracking-scraper" rel="noopener noreferrer"&gt;DHL Tracking Scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;USD 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postal services and other carriers on 17TRACK&lt;/td&gt;
&lt;td&gt;&lt;a href="https://apify.com/muhammadafzal/17track-package-tracking-scraper" rel="noopener noreferrer"&gt;17TRACK Package Tracking Scraper&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;USD 39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mixed UPS and FedEx International Connect, one status vocabulary&lt;/td&gt;
&lt;td&gt;&lt;a href="https://apify.com/muhammadafzal/multi-carrier-package-tracking" rel="noopener noreferrer"&gt;Multi-Carrier Package Tracking&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;USD 40&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each Actor reads the carrier's public tracking page (or 17TRACK's public tracker), so none of them needs a carrier login, OAuth app or API key.&lt;/p&gt;

&lt;h2&gt;
  
  
  When should you use the official carrier tracking APIs instead?
&lt;/h2&gt;

&lt;p&gt;Use the official UPS, FedEx or DHL tracking API when you already have developer access, need labels, rates, address changes or proof-of-delivery documents, or want push notifications tied to your shipping account. That is what those APIs are for.&lt;/p&gt;

&lt;p&gt;The approach here fits a narrower job: you already have tracking numbers, often from several shippers, marketplaces or 3PLs, and you only need their current status in a structured format. You skip three registrations, three auth flows and three SDKs. The trade-offs are real: you get what the public tracking pages show, lookups take seconds each rather than milliseconds, and nothing is pushed to you, so you poll on a schedule.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js 18 or newer (Python 3.11 or newer for the Python example)&lt;/li&gt;
&lt;li&gt;A free Apify account and your API token (Apify Console → Settings → API &amp;amp; Integrations)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm install apify-client&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_token_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Route each tracking number to the right Actor
&lt;/h2&gt;

&lt;p&gt;Most order systems already store the carrier, so the input file can carry it. When a row has no carrier, two formats are safe to detect: &lt;code&gt;1Z&lt;/code&gt; plus 16 characters is UPS, and 12 or 15 digits is usually FedEx. Everything else goes to 17TRACK, which detects the carrier itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;carrier,trackingNumber
fedex,794644790138
ups,1Z999AA10123456784
dhl,00340434292135100186
,LX123456789CN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;detectCarrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^1Z&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;0-9A-Z&lt;/span&gt;&lt;span class="se"&gt;]{16}&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ups&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(\d{12}&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;\d{15})&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fedex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;other&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 17TRACK detects the carrier&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DHL numbers come in too many shapes to detect safely, so label them in the file. An unlabelled DHL number still works through 17TRACK, it just costs more. When 17TRACK can't tell a number's carrier, the run reports it without charging, and you can rerun it with the 17TRACK &lt;code&gt;carrier&lt;/code&gt; code (FedEx is &lt;code&gt;100003&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Describe the four trackers once
&lt;/h2&gt;

&lt;p&gt;Each Actor has its own batch size and input fields. Keeping them in one table makes the rest of the script carrier-agnostic:&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;const&lt;/span&gt; &lt;span class="nx"&gt;ACTORS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;fedex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;muhammadafzal/fedex-package-tracking-scraper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;batch&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="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;trackingNumbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;includeDetailedScans&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;maxResults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;ups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;muhammadafzal/ups-package-tracking-scraper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;batch&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="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.03&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;trackingNumbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;dhl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;muhammadafzal/dhl-package-tracking-scraper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;batch&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="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;trackingNumbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demoMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accessMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;muhammadafzal/17track-package-tracking-scraper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;batch&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="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.039&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;trackingNumbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;}),&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;Three settings matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;timeout&lt;/code&gt;&lt;/strong&gt; is the run timeout in seconds. Lookups run one at a time, and a full FedEx batch of 30 takes several minutes, so FedEx and UPS get more than the 300-second default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;price&lt;/code&gt;&lt;/strong&gt; is the FREE-tier price per record, used below to set a spend cap per run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;demoMode: false&lt;/code&gt;&lt;/strong&gt; for DHL. The DHL Actor's default input runs DHL's sample number &lt;code&gt;7777777770&lt;/code&gt;, which returns a demo record labelled &lt;code&gt;isDemoData: true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Normalize four output shapes into one
&lt;/h2&gt;

&lt;p&gt;The Actors return the carrier's own vocabulary, so field names differ. A small mapper gives you one row shape:&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;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fedex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FedEx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tracking_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="na"&gt;eta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;estimated_delivery_date&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actual_delivery_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;last_scan&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ups&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="na"&gt;eta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;estimatedDelivery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastEvent&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dhl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DHL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="na"&gt;eta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;estimatedDelivery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentLocation&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;carriers&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &amp;gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;eta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;estimatedDelivery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latestEvent&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;};&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;If you need more than the summary, every record carries more: FedEx adds &lt;code&gt;status_code&lt;/code&gt;, &lt;code&gt;service&lt;/code&gt;, &lt;code&gt;ship_date&lt;/code&gt;, &lt;code&gt;package_count&lt;/code&gt; and the full &lt;code&gt;scan_events&lt;/code&gt;; UPS adds a &lt;code&gt;status&lt;/code&gt; category, &lt;code&gt;terminal&lt;/code&gt;, &lt;code&gt;delivered&lt;/code&gt;, &lt;code&gt;delayed&lt;/code&gt;, &lt;code&gt;deliveredTo&lt;/code&gt; and &lt;code&gt;receivedBy&lt;/code&gt;; DHL adds &lt;code&gt;statusCode&lt;/code&gt;, origin and destination fields and &lt;code&gt;events&lt;/code&gt;; 17TRACK adds &lt;code&gt;statusCategory&lt;/code&gt;, &lt;code&gt;originCountry&lt;/code&gt;, &lt;code&gt;destinationCountry&lt;/code&gt;, &lt;code&gt;daysInTransit&lt;/code&gt; and &lt;code&gt;events&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Run the batches and write one CSV
&lt;/h2&gt;

&lt;p&gt;Carriers run in parallel, and batches within a carrier run one after another, so at most four runs are active at once. Each run gets a spend cap of its batch size times the record price plus a cent.&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="c1"&gt;// track-all.mjs  →  node track-all.mjs shipments.csv&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;writeFile&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:fs/promises&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApifyClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;apify-client&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APIFY_TOKEN&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// ACTORS, detectCarrier() and normalize() from the steps above&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fedex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;ups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;dhl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&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;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shipments.csv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\r?\n&lt;/span&gt;&lt;span class="sr"&gt;/&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;const&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;lines&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&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;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;second&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[\s&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// header or blank line&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;carrier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;first&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;detectCarrier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;other&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nums&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;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ACTORS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxTotalChargeUsd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultDatasetId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;listItems&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; records, see run &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&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;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isDemoData&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&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;perCarrier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="kd"&gt;set&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;rows&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="nx"&gt;ACTORS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;runBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;ACTORS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;)));&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;rows&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;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;perCarrier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flat&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;cell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`"&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/"/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;""&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&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;csv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;carrier,trackingNumber,status,eta,lastLocation&lt;/span&gt;&lt;span class="dl"&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;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;carrier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trackingNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastLocation&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))];&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tracking-status.csv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; records written to tracking-status.csv`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A FedEx record before normalization looks like this (shortened, values illustrative):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tracking_number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"794644790138"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"carrier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FedEx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Delivered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"actual_delivery_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-20T13:12:00-05:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FedEx Ground"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"last_scan"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-10-20T13:12:00-05:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Delivered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DALLAS, TX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"event_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DL"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scan_events"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"... full scan history ..."&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tracking_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.fedex.com/fedextrack/?trknbr=794644790138"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Find out why a number returned nothing
&lt;/h2&gt;

&lt;p&gt;A typo, a label that was never scanned, an expired record or a refused lookup produces no record, and none of the Actors invents a row for it or charges for it. Each run explains every missing number in its key-value store: the record is called &lt;code&gt;SUMMARY&lt;/code&gt; for FedEx and DHL, and &lt;code&gt;OUTPUT&lt;/code&gt; for UPS, 17TRACK and Multi-Carrier. Add this inside &lt;code&gt;runBatch&lt;/code&gt;, after the run finishes:&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;const&lt;/span&gt; &lt;span class="nx"&gt;KV_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fedex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SUMMARY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;dhl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SUMMARY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ups&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OUTPUT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OUTPUT&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;record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keyValueStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defaultKeyValueStoreId&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;KV_KEY&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;record&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The outcome is one of &lt;code&gt;DATA&lt;/code&gt;, &lt;code&gt;EMPTY&lt;/code&gt; (the carrier has no record), &lt;code&gt;REJECTED&lt;/code&gt; (malformed number), &lt;code&gt;BLOCKED&lt;/code&gt; (the carrier refused the lookup) or &lt;code&gt;FAILED&lt;/code&gt; (timeout or page error). UPS and Multi-Carrier mask tracking numbers in their diagnostics, so those records are safe to paste into a ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same call from Python
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"apify-client&amp;gt;=3.3,&amp;lt;4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;apify_client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ApifyClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ApifyClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;actor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;muhammadafzal/ups-package-tracking-scraper&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;run_input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trackingNumbers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1Z999AA10123456784&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;locale&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en_US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_dataset_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;iterate_items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trackingNumber&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;terminal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lastEvent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;apify-client&lt;/code&gt; 3.x, &lt;code&gt;call()&lt;/code&gt; returns a &lt;code&gt;Run&lt;/code&gt; object, so read &lt;code&gt;run.default_dataset_id&lt;/code&gt; rather than &lt;code&gt;run["defaultDatasetId"]&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When does Multi-Carrier Package Tracking make sense?
&lt;/h2&gt;

&lt;p&gt;Use &lt;a href="https://apify.com/muhammadafzal/multi-carrier-package-tracking" rel="noopener noreferrer"&gt;Multi-Carrier Package Tracking&lt;/a&gt; when you want UPS scan-by-scan history, or when one list mixes UPS and FedEx International Connect (&lt;code&gt;KOT&lt;/code&gt;, &lt;code&gt;PRO&lt;/code&gt;) numbers and you want one status vocabulary: &lt;code&gt;pre_advice&lt;/code&gt;, &lt;code&gt;accepted&lt;/code&gt;, &lt;code&gt;in_transit&lt;/code&gt;, &lt;code&gt;out_for_delivery&lt;/code&gt;, &lt;code&gt;delayed&lt;/code&gt;, &lt;code&gt;delivery_attempted&lt;/code&gt;, &lt;code&gt;ready_for_pickup&lt;/code&gt;, &lt;code&gt;delivered&lt;/code&gt;, &lt;code&gt;returned&lt;/code&gt;, &lt;code&gt;exception&lt;/code&gt; or &lt;code&gt;unknown&lt;/code&gt;. It takes 25 numbers per run with &lt;code&gt;carrier: "auto"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two honest limits: standard 12- and 15-digit FedEx numbers are accepted there but not yet verified, so send those to FedEx Tracking Scraper; and USPS lookups are currently refused and end as &lt;code&gt;BLOCKED&lt;/code&gt;, with no result charge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it every morning
&lt;/h2&gt;

&lt;p&gt;Save the input in Apify Console and attach a schedule (hourly, daily or any cron expression), or run the script from your own cron. UPS and Multi-Carrier records carry &lt;code&gt;terminal: true&lt;/code&gt; once a package is delivered or returned, so each run you can drop those numbers and re-check only what is still moving. Apify can also call a webhook when each run finishes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn it into an AI agent: Claude, ChatGPT, Codex, Gemini, Grok and Cursor
&lt;/h2&gt;

&lt;p&gt;The script above is one way to drive the trackers. The other is to hand them to an AI agent. All five Actors are exposed as tools through Apify's MCP server. Any assistant that speaks MCP can then read each tool's input schema, output fields and price per record, pick the right tracker for each number, run it, and reason over the JSON that comes back. You describe the job in plain language instead of writing the routing and normalization yourself.&lt;/p&gt;

&lt;p&gt;This is the server URL with only the five trackers enabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://mcp.apify.com/?tools=muhammadafzal/fedex-package-tracking-scraper,muhammadafzal/ups-package-tracking-scraper,muhammadafzal/dhl-package-tracking-scraper,muhammadafzal/17track-package-tracking-scraper,muhammadafzal/multi-carrier-package-tracking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It signs you in to Apify with OAuth on first connect. Clients that can't do OAuth send &lt;code&gt;Authorization: Bearer &amp;lt;APIFY_TOKEN&amp;gt;&lt;/code&gt; instead. Save the URL once, since the snippets below use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;APIFY_MCP_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.apify.com/?tools=muhammadafzal/fedex-package-tracking-scraper,muhammadafzal/ups-package-tracking-scraper,muhammadafzal/dhl-package-tracking-scraper,muhammadafzal/17track-package-tracking-scraper,muhammadafzal/multi-carrier-package-tracking"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Claude (claude.ai, Claude Desktop, Claude Code)
&lt;/h3&gt;

&lt;p&gt;In claude.ai or Claude Desktop, open Settings → Connectors, choose &lt;strong&gt;Add custom connector&lt;/strong&gt;, paste the URL and sign in to Apify. In Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http apify &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_MCP_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# then run /mcp inside Claude Code to sign in&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ChatGPT
&lt;/h3&gt;

&lt;p&gt;Turn on Developer Mode in ChatGPT's settings, create a connector with the URL as the MCP server and OAuth as the authentication, then enable it from the tools menu in a chat. Developer Mode is available on paid plans, and workspace admins may need to allow custom connectors.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenAI Codex
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codex mcp add apify &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_MCP_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
codex mcp login apify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or put it in &lt;code&gt;~/.codex/config.toml&lt;/code&gt; and use a token instead of OAuth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="k"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mcp_servers&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apify&lt;/span&gt;&lt;span class="k"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"https://mcp.apify.com/?tools=muhammadafzal/fedex-package-tracking-scraper,muhammadafzal/ups-package-tracking-scraper,muhammadafzal/dhl-package-tracking-scraper,muhammadafzal/17track-package-tracking-scraper,muhammadafzal/multi-carrier-package-tracking"&lt;/span&gt;
&lt;span class="n"&gt;bearer_token_env_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"APIFY_TOKEN"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gemini CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http apify &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$APIFY_MCP_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# then run /mcp auth apify inside Gemini CLI to sign in&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a headless machine, skip OAuth and pass &lt;code&gt;--header "Authorization: Bearer &amp;lt;APIFY_TOKEN&amp;gt;"&lt;/code&gt; instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grok (xAI API)
&lt;/h3&gt;

&lt;p&gt;Grok connects to remote MCP servers from the API, so the agent runs in your own code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;xai_sdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;xai_sdk.chat&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;xai_sdk.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;XAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grok-4.7&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# use the current Grok model
&lt;/span&gt;    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;server_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APIFY_MCP_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;server_label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;extra_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;APIFY_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Track 1Z999AA10123456784 and 794644790138. Which ones are delayed?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cursor and other MCP clients
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;apify mcp install cursor&lt;/code&gt; writes the Cursor config for you. VS Code, Windsurf and any other client that accepts a remote MCP server work with the same URL. For a client without remote MCP support, run the server locally with &lt;code&gt;npx -y @apify/actors-mcp-server&lt;/code&gt; and &lt;code&gt;APIFY_TOKEN&lt;/code&gt; set.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent automation recipes
&lt;/h2&gt;

&lt;p&gt;Once the tools are connected, these are prompts you can give the agent as they are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Morning exception report.&lt;/strong&gt; "Read &lt;code&gt;open-orders.csv&lt;/code&gt;. Track every number with the right tracker. List the packages that are delayed, have a failed delivery attempt, or have had no new scan for three days, each with its last scan location. Draft a short message for each customer." To run it unattended, call Claude Code from cron:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# every weekday at 07:00&lt;/span&gt;
0 7 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; 1-5 &lt;span class="nb"&gt;cd&lt;/span&gt; ~/ops &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; claude &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;morning-report-prompt.txt&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--allowedTools&lt;/span&gt; &lt;span class="s2"&gt;"mcp__apify,Read,Write"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;codex exec&lt;/code&gt; and &lt;code&gt;gemini -p&lt;/code&gt; run the same prompt non-interactively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support-ticket answers.&lt;/strong&gt; Give a support agent the tools and let it answer "where is my order?" itself. It tracks the number on the ticket, reads &lt;code&gt;statusCategory&lt;/code&gt; or &lt;code&gt;status&lt;/code&gt; and the latest event, and writes the reply with the real delivery estimate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stop re-checking finished packages.&lt;/strong&gt; UPS and Multi-Carrier records carry &lt;code&gt;terminal: true&lt;/code&gt; once a package is delivered or returned. Tell the agent to drop those numbers from tomorrow's list, so each run only checks what is still moving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-border explanations.&lt;/strong&gt; 17TRACK records list every carrier a parcel passed through, with origin and destination countries. The agent can explain a handoff such as "left China Post and is now with USPS in Chicago" in plain words.&lt;/p&gt;

&lt;p&gt;Every call returns structured records and honest outcomes. A number with no data comes back as &lt;code&gt;EMPTY&lt;/code&gt;, a refused lookup as &lt;code&gt;BLOCKED&lt;/code&gt;, and nothing is invented, so the agent never has to tell a guess from a fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does it cost?
&lt;/h2&gt;

&lt;p&gt;Prices are per record delivered, plus a start fee per run. Paid Apify plans get the same or lower per-record prices.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Actor&lt;/th&gt;
&lt;th&gt;FREE, per 1,000 records&lt;/th&gt;
&lt;th&gt;GOLD and above, per 1,000&lt;/th&gt;
&lt;th&gt;Start fee per run&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FedEx Tracking Scraper&lt;/td&gt;
&lt;td&gt;USD 20&lt;/td&gt;
&lt;td&gt;USD 17&lt;/td&gt;
&lt;td&gt;USD 0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UPS Tracking Scraper&lt;/td&gt;
&lt;td&gt;USD 30&lt;/td&gt;
&lt;td&gt;USD 22&lt;/td&gt;
&lt;td&gt;USD 0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DHL Tracking Scraper&lt;/td&gt;
&lt;td&gt;USD 20&lt;/td&gt;
&lt;td&gt;USD 17&lt;/td&gt;
&lt;td&gt;USD 0.00005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;17TRACK Package Tracking Scraper&lt;/td&gt;
&lt;td&gt;USD 39&lt;/td&gt;
&lt;td&gt;USD 31.20&lt;/td&gt;
&lt;td&gt;USD 0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-Carrier Package Tracking&lt;/td&gt;
&lt;td&gt;USD 40&lt;/td&gt;
&lt;td&gt;USD 32&lt;/td&gt;
&lt;td&gt;USD 0.005&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Multi-Carrier's price applies from 6 November 2026; before that date it is USD 20 per 1,000 on FREE. The start fee is charged per started GB of run memory, which is one start event at each Actor's default memory.&lt;/p&gt;

&lt;p&gt;A worked example: 500 numbers split into 200 FedEx, 150 UPS, 100 DHL and 50 others, every one returning a record, on the FREE tier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FedEx: 7 runs, 200 × 0.020 + 7 × 0.005 = USD 4.04&lt;/li&gt;
&lt;li&gt;UPS: 6 runs, 150 × 0.030 + 6 × 0.005 = USD 4.53&lt;/li&gt;
&lt;li&gt;DHL: 10 runs, 100 × 0.020 + 10 × 0.00005 = USD 2.00&lt;/li&gt;
&lt;li&gt;17TRACK: 5 runs, 50 × 0.039 + 5 × 0.005 = USD 1.98&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total: about USD 12.54&lt;/strong&gt;, less for any number that returns nothing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do I need a UPS, FedEx or DHL developer account?
&lt;/h3&gt;

&lt;p&gt;No. You need an Apify account and its API token. If you already have a DHL developer key, the DHL Actor can use DHL's official API instead of the public page: put it in &lt;code&gt;dhlApiKey&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a free package tracking API?
&lt;/h3&gt;

&lt;p&gt;These Actors charge per record, with no subscription. Apify's Free plan includes USD 5 of usage per month, and pay-per-event charges draw on it, so you can test a couple of hundred FedEx or DHL lookups before paying anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which AI assistants can use these trackers?
&lt;/h3&gt;

&lt;p&gt;Any MCP client: Claude (claude.ai, Claude Desktop, Claude Code), ChatGPT with Developer Mode, OpenAI Codex, Gemini CLI, Grok through the xAI API, Cursor, VS Code and others. They all connect to the same Apify MCP server URL; the setup for each is in the agent section above.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many packages can I track at once?
&lt;/h3&gt;

&lt;p&gt;30 FedEx, 25 UPS, 25 Multi-Carrier, 10 DHL or 10 17TRACK numbers per run. For longer lists, start more runs, as the script does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does this track USPS?
&lt;/h3&gt;

&lt;p&gt;Not reliably right now. Multi-Carrier Package Tracking recognizes USPS formats, but the lookups are currently refused and end as &lt;code&gt;BLOCKED&lt;/code&gt; without a result charge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the data real-time?
&lt;/h3&gt;

&lt;p&gt;Each record is what the carrier's public page showed at &lt;code&gt;scrapedAt&lt;/code&gt;, &lt;code&gt;scraped_at&lt;/code&gt; or &lt;code&gt;retrievedAt&lt;/code&gt;. There is no push feed; schedule runs as often as you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Am I charged for numbers that are not found?
&lt;/h3&gt;

&lt;p&gt;No. Not-found, invalid, blocked and failed numbers write no record and pay no record charge. The start fee still applies to the run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits worth knowing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;These Actors read public tracking pages. They don't create labels, quote rates, change deliveries or download proof-of-delivery signatures.&lt;/li&gt;
&lt;li&gt;Carriers hide some fields by service, destination and shipment age, and old tracking records expire. New labels can take 24–48 hours to show events.&lt;/li&gt;
&lt;li&gt;Lookups are sequential inside a run, so a full FedEx batch takes minutes, not seconds.&lt;/li&gt;
&lt;li&gt;Track only shipments you send, receive or are authorized to monitor. Records can include delivery locations and recipient text, so treat the output as personal data.&lt;/li&gt;
&lt;li&gt;The Actors are unofficial and not affiliated with UPS, FedEx, DHL or 17TRACK; the names identify the public sources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apify.com/muhammadafzal/fedex-package-tracking-scraper" rel="noopener noreferrer"&gt;FedEx Tracking Scraper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apify.com/muhammadafzal/ups-package-tracking-scraper" rel="noopener noreferrer"&gt;UPS Tracking Scraper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apify.com/muhammadafzal/dhl-package-tracking-scraper" rel="noopener noreferrer"&gt;DHL Tracking Scraper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apify.com/muhammadafzal/17track-package-tracking-scraper" rel="noopener noreferrer"&gt;17TRACK Package Tracking Scraper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apify.com/muhammadafzal/multi-carrier-package-tracking" rel="noopener noreferrer"&gt;Multi-Carrier Package Tracking&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your carrier mix includes a format this routing gets wrong, tell me in the comments and I'll add it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>javascript</category>
      <category>python</category>
      <category>scraper</category>
    </item>
    <item>
      <title>A Free Chrome Extension to Audit llms.txt, robots.txt, ACP, and UCP Readiness on Any Site</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Mon, 17 Aug 2026 12:12:08 +0000</pubDate>
      <link>https://dev.to/aws-builders/a-free-chrome-extension-to-audit-llmstxt-robotstxt-acp-and-ucp-readiness-on-any-site-4eoo</link>
      <guid>https://dev.to/aws-builders/a-free-chrome-extension-to-audit-llmstxt-robotstxt-acp-and-ucp-readiness-on-any-site-4eoo</guid>
      <description>&lt;p&gt;A Free Chrome Extension to Audit llms.txt, robots.txt, ACP, and UCP Readiness on Any Site&lt;/p&gt;

&lt;p&gt;If you've shipped an llms.txt file recently, you've probably asked yourself the same question I did: does this actually work, or did I just create a file that returns a 404 with a 200 status code?&lt;/p&gt;

&lt;p&gt;There's no linter for llms.txt yet. There's no curl one-liner that checks whether your Markdown alternates resolve, whether your robots.txt is blocking the wrong agents, or whether your product catalog exposes anything an ACP- or UCP-aware shopping agent could parse. So most of us either skip the verification step entirely or write a throwaway script and forget to maintain it.&lt;/p&gt;

&lt;p&gt;Clustova AI Readiness Inspector is a Chrome extension that does this verification for you, on demand, on whatever page you currently have open.&lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://chromewebstore.google.com/detail/clustova-ai-readiness-ins/jkennecpgkjjjkckkjioanljdfdiolab" rel="noopener noreferrer"&gt;Clustova AI Readiness Inspector on the Chrome Web Store&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The problem it solves&lt;/p&gt;

&lt;p&gt;AI agents and answer engines now consume websites through a few emerging channels that traditional SEO tooling doesn't check:&lt;/p&gt;

&lt;p&gt;Signal  What it is  Why it's easy to get wrong&lt;br&gt;
llms.txt    A root or path-scoped file that tells AI systems what content is available and how it's structured  Easy to publish with broken links or malformed sections, no standard validator&lt;br&gt;
llms-full.txt   An optional convention exposing a fuller, single-file version of a site's content   New and inconsistently adopted, easy to forget to update&lt;br&gt;
Markdown alternates A .md version of an HTML page, or content that converts cleanly to Markdown HTML-to-Markdown conversion quality varies a lot depending on markup&lt;br&gt;
robots.txt / sitemaps   Classic crawl directives, still relevant to AI crawlers Often written years ago for search bots only, never revisited for AI agents&lt;br&gt;
UCP Universal Commerce Protocol discovery and profile metadata  Requires public metadata most sites haven't published&lt;br&gt;
ACP Agentic Commerce Protocol product or integration evidence   New enough that most teams haven't heard of it yet&lt;/p&gt;

&lt;p&gt;None of these are things a Lighthouse audit or a standard SEO crawler checks for you.&lt;/p&gt;

&lt;p&gt;How the extension works, technically&lt;/p&gt;

&lt;p&gt;The extension is scoped narrowly on purpose:&lt;/p&gt;

&lt;p&gt;It runs only on the active tab, and only after you click it. No persistent background access to every domain you visit.&lt;br&gt;
The scan logic runs locally inside the extension.&lt;br&gt;
Where it needs to verify something public, like fetching robots.txt, checking for llms.txt, or sampling a linked resource, it sends the request directly from your browser to the site being inspected. Nothing routes through a Clustova server for the core scan.&lt;br&gt;
It does not load or execute remote JavaScript or WebAssembly.&lt;br&gt;
It doesn't touch cookies, passwords, form data, or browser history, and it can't create checkout sessions or submit order data even on commerce sites.&lt;/p&gt;

&lt;p&gt;That last point matters if you're evaluating this for use inside a team or agency: it's a read-only, publicly-observable-evidence tool, not something that mutates state on the sites it inspects.&lt;/p&gt;

&lt;p&gt;What a scan actually returns&lt;/p&gt;

&lt;p&gt;Run the extension on a page and you get a structured report covering:&lt;/p&gt;

&lt;p&gt;llms.txt discovery and validation — root-level and path-scoped detection, structural validation, and a sample check on linked resources&lt;br&gt;
llms-full.txt check — whether the optional full-content file exists&lt;br&gt;
Markdown readiness — detection of Markdown versions of the current page, a review of Markdown media types and content quality, and how well the HTML converts to Markdown&lt;br&gt;
Crawl and index basics — robots.txt, XML sitemap presence, HTTPS, and public metadata&lt;br&gt;
UCP discovery — public commerce profile metadata, if present&lt;br&gt;
ACP evidence — public product or integration signals for agentic commerce, if present (these checks only trigger when the site looks commerce-related)&lt;/p&gt;

&lt;p&gt;Each check comes back with the evidence found, a status, any relevant limitations, and remediation guidance where something's missing or malformed.&lt;/p&gt;

&lt;p&gt;From there you can:&lt;/p&gt;

&lt;p&gt;Open the full findings in Chrome's side panel&lt;br&gt;
Export the report as Markdown or JSON, which is genuinely useful if you want to pipe it into a CI check, paste it into a GitHub issue, or hand it to a teammate&lt;br&gt;
Keep a local history of recent scans in Chrome, so you can diff a site before and after a fix&lt;/p&gt;

&lt;p&gt;There's also an optional Deep scan link into Clustova's web-based checker for a more exhaustive review, but that runs on their site under their own policy, separate from the local extension scan.&lt;/p&gt;

&lt;p&gt;A quick workflow for developers&lt;br&gt;
Ship or update your llms.txt.&lt;br&gt;
Open the page in Chrome and run the extension.&lt;br&gt;
Export the JSON report.&lt;br&gt;
Fix whatever comes back red, broken links in llms.txt, a missing sitemap entry, a Markdown alternate that 404s.&lt;br&gt;
Re-scan and diff against the local history to confirm the fix landed.&lt;br&gt;
Repeat before every major content or catalog change, the same way you'd re-run a Lighthouse audit after a perf change.&lt;/p&gt;

&lt;p&gt;If you're on an e-commerce stack and exploring agentic checkout, steps 2 through 5 are exactly what you'd want to run before and after wiring up ACP or UCP metadata, since there's currently no other quick way to confirm those signals are actually publicly visible.&lt;/p&gt;

&lt;p&gt;Be clear about what it isn't&lt;/p&gt;

&lt;p&gt;Worth stating directly, because the extension's own documentation says this too: a clean report doesn't guarantee AI search ranking, citation, inclusion, protocol compliance, or transaction eligibility. It confirms that the publicly observable groundwork is in place, which is a prerequisite, not a promise. Treat it the way you'd treat a passing schema.org validator: necessary, not sufficient.&lt;/p&gt;

&lt;p&gt;Try it&lt;/p&gt;

&lt;p&gt;Install it from the Chrome Web Store, run it on your own site first, then run it on a competitor's. The gaps you'll find are usually more informative than the passes.&lt;/p&gt;

&lt;p&gt;Clustova AI Readiness Inspector&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>chrome</category>
      <category>ai</category>
    </item>
    <item>
      <title>10 MCP Servers Every Developer Should Be Using in 2026</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Sat, 28 Mar 2026 21:36:38 +0000</pubDate>
      <link>https://dev.to/mafzal9/10-mcp-servers-every-developer-should-be-using-in-2026-55c7</link>
      <guid>https://dev.to/mafzal9/10-mcp-servers-every-developer-should-be-using-in-2026-55c7</guid>
      <description>&lt;p&gt;&lt;em&gt;If you're using Claude or Cursor and haven't set up MCP servers yet, you're leaving a massive amount of productivity on the table.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What is MCP and Why Should You Care?
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol (MCP) is an open standard created by Anthropic that lets AI assistants like Claude connect to real-world tools and systems. Instead of copy-pasting code snippets in and out of your AI chat, MCP lets Claude directly read your files, query your database, push to GitHub, search the web and run terminal commands — all within a single conversation.&lt;/p&gt;

&lt;p&gt;Think of it as giving your AI assistant hands.&lt;/p&gt;

&lt;p&gt;Before MCP, every AI integration was a custom one-off build. Now there's one standard protocol that works across Claude Desktop, Cursor, Cline, Zed and any other MCP-compatible client. Build a server once, use it everywhere.&lt;/p&gt;

&lt;p&gt;The ecosystem has exploded. There are now over 1000 MCP servers covering everything from database management to browser automation to Stripe payments. Finding the good ones used to mean scrolling through a flat GitHub README. That's why I built &lt;a href="https://www.mcpcmd.com" rel="noopener noreferrer"&gt;MCPCMD&lt;/a&gt; — a curated directory of 1000+ MCP servers organized by category with install commands and config snippets on every page.&lt;/p&gt;

&lt;p&gt;But enough about that. Here are the 10 servers I actually use and recommend.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. GitHub MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Version Control&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @github/mcp-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The official GitHub MCP server is the one that made me a true believer. You can ask Claude to search your repos, read any file from any public repo, create issues, open pull requests, manage branches and review GitHub Actions runs — all from a conversation.&lt;/p&gt;

&lt;p&gt;The killer use case: paste a bug report into Claude and say "find the relevant code in my repo and open a draft PR with a fix." It does it. The whole thing.&lt;/p&gt;

&lt;p&gt;It works as both a local server (using a Personal Access Token) and a remote server (via OAuth), so you can share it across machines without managing credentials manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"github"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.githubcopilot.com/mcp/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer YOUR_TOKEN"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Supabase MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Databases&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @supabase/mcp-server-supabase&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you use Supabase, this one is a no-brainer. The official Supabase MCP server lets Claude query your database, manage auth, inspect your schema and even deploy edge functions — all with natural language.&lt;/p&gt;

&lt;p&gt;Instead of jumping between the Supabase dashboard, your SQL editor and your codebase, you can stay in one place and ask things like "show me all users who signed up in the last 7 days and haven't completed onboarding."&lt;/p&gt;

&lt;p&gt;The server respects your Supabase user permissions, so it's not giving Claude access to anything it shouldn't have.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Playwright MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Browser Automation&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @playwright/mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the one that feels like magic the first time you use it. Playwright MCP gives Claude control of a real browser. You can ask it to navigate to a URL, fill out a form, click elements, take screenshots and extract content from pages — all programmatically.&lt;/p&gt;

&lt;p&gt;Practical uses I've actually done with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Go to this competitor's pricing page and summarize their tiers"&lt;/li&gt;
&lt;li&gt;"Fill out this form with these test values and screenshot the result"&lt;/li&gt;
&lt;li&gt;"Scrape the last 20 posts from this public forum and give me a summary"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs a real Chromium instance so it handles JavaScript-heavy sites that simple fetch-based scrapers miss.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Context7 MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Developer Tools&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @upstash/context7-mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One of the most underrated servers on this list. Context7 solves a specific and painful problem: AI assistants get confused by outdated library documentation because their training data has a cutoff.&lt;/p&gt;

&lt;p&gt;Context7 pulls live, up-to-date documentation for thousands of libraries and injects the relevant parts into your Claude conversation. So when you ask "how do I set up streaming with the latest version of the Vercel AI SDK?", Claude answers based on the actual current docs, not something from 18 months ago.&lt;/p&gt;

&lt;p&gt;If you do a lot of coding with Claude, install this one immediately. It dramatically reduces hallucinated API calls.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Firecrawl MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Browser Automation&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx firecrawl-mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Firecrawl is the best web scraping and crawling server in the ecosystem right now. It goes beyond simple page fetching — it can crawl entire sites, handle JavaScript rendering, clean up the output into structured markdown and even extract specific data patterns.&lt;/p&gt;

&lt;p&gt;Use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Research tasks where you need to pull content from multiple pages&lt;/li&gt;
&lt;li&gt;Turning any website into a knowledge base Claude can reason over&lt;/li&gt;
&lt;li&gt;Competitive analysis at scale&lt;/li&gt;
&lt;li&gt;Content migration projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It requires a Firecrawl API key (free tier available) but the quality of the output is significantly better than basic fetch-based alternatives.&lt;/p&gt;


&lt;h2&gt;
  
  
  6. MCP Filesystem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; File System&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @modelcontextprotocol/server-filesystem ~/your-directory&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the official reference implementation from Anthropic and the one most people install first. It gives Claude secure, sandboxed access to read, write, search and manage files in directories you explicitly specify.&lt;/p&gt;

&lt;p&gt;You control exactly which folders are accessible. Claude cannot touch anything outside those paths.&lt;/p&gt;

&lt;p&gt;Everyday uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Read all the markdown files in my notes folder and give me a weekly summary"&lt;/li&gt;
&lt;li&gt;"Find all TODO comments in my src directory"&lt;/li&gt;
&lt;li&gt;"Rename all files in this folder to follow kebab-case"&lt;/li&gt;
&lt;li&gt;"Create a new component file following the pattern of these existing ones"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's simple but it removes one of the most annoying parts of working with AI: constantly copy-pasting file contents in and out of the chat.&lt;/p&gt;


&lt;h2&gt;
  
  
  7. Notion MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Productivity&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @notionhq/notion-mcp-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The official Notion server lets Claude search, read and manage your Notion workspace. If Notion is your second brain, this makes Claude a genuine extension of it.&lt;/p&gt;

&lt;p&gt;Useful patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Find my notes on authentication from last month and summarize the key decisions"&lt;/li&gt;
&lt;li&gt;"Create a new page in my Projects database with this spec"&lt;/li&gt;
&lt;li&gt;"What meetings do I have documented in my work log from this week?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Requires a Notion integration token which takes about 2 minutes to set up through the Notion developer portal.&lt;/p&gt;


&lt;h2&gt;
  
  
  8. Chrome DevTools MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Developer Tools&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @chrome-devtools/mcp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This one is particularly interesting for web developers. Chrome DevTools MCP lets AI agents connect to a live Chrome browser session and interact with it programmatically — inspecting the DOM, reading console logs, monitoring network requests and debugging JavaScript.&lt;/p&gt;

&lt;p&gt;Imagine asking Claude "look at this page I have open and tell me why the layout is breaking on mobile" and having it actually inspect the live DOM rather than guessing from a screenshot. That's what this enables.&lt;/p&gt;

&lt;p&gt;Still relatively new but the potential for debugging workflows is enormous.&lt;/p&gt;


&lt;h2&gt;
  
  
  9. Neon MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; Databases&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @neondatabase/mcp-server-neon&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you use Neon for serverless PostgreSQL, this is the official server from the Neon team. It lets Claude create and manage databases, run queries, handle branching and work with your schema — all through natural language.&lt;/p&gt;

&lt;p&gt;The branching feature is particularly clever. You can ask Claude to "create a branch, run this migration, verify the results and then merge it back" as a single operation. That's a database workflow that normally takes 10 minutes compressed into one prompt.&lt;/p&gt;


&lt;h2&gt;
  
  
  10. Brave Search MCP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Category:&lt;/strong&gt; APIs &amp;amp; Integrations&lt;br&gt;
&lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;npx @modelcontextprotocol/server-brave-search&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The simplest one on this list but one of the most useful. Brave Search MCP gives Claude access to real-time web search so it can look things up during a conversation without you having to switch tabs and paste content in manually.&lt;/p&gt;

&lt;p&gt;Ask it anything that requires current information — recent library releases, news, prices, documentation that might have changed. It uses Brave's search API (free tier: 2000 queries/month) and returns clean results Claude can reason over immediately.&lt;/p&gt;


&lt;h2&gt;
  
  
  How to Install Any of These
&lt;/h2&gt;

&lt;p&gt;Every server on this list follows the same pattern:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Make sure you have Node.js 18+ installed&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Open your Claude Desktop config file&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS: &lt;code&gt;~/Library/Application Support/Claude/claude_desktop_config.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Add the server config inside &lt;code&gt;mcpServers&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"filesystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/Users/you/Documents"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"brave-search"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@modelcontextprotocol/server-brave-search"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"BRAVE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-key-here"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Restart Claude Desktop&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's it. The tools appear automatically in your next conversation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Find More
&lt;/h2&gt;

&lt;p&gt;This list barely scratches the surface. There are 1000+ MCP servers covering databases, cloud platforms, communication tools, finance APIs, monitoring and a lot more.&lt;/p&gt;

&lt;p&gt;If you want to browse them all in one place, check out &lt;a href="https://www.mcpcmd.com" rel="noopener noreferrer"&gt;MCPCMD&lt;/a&gt; — it's a curated directory with install commands and config snippets on every page, organized across 20 categories.&lt;/p&gt;

&lt;p&gt;If you've built an MCP server yourself, you can submit it for free. The directory is updated daily.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Are You Using?
&lt;/h2&gt;

&lt;p&gt;Drop a comment with the MCP servers you're finding most useful. I'm especially curious about anything in the AI &amp;amp; ML and Cloud &amp;amp; DevOps categories — those move fast and there are probably gems I haven't found yet.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;ai&lt;/code&gt; &lt;code&gt;productivity&lt;/code&gt; &lt;code&gt;claude&lt;/code&gt; &lt;code&gt;llm&lt;/code&gt; &lt;code&gt;developer-tools&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Beyond Swag: Unveiling the Profound Impact of Community Engagement on My Journey to Authorship</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Tue, 16 Jan 2024 05:52:48 +0000</pubDate>
      <link>https://dev.to/aws-builders/beyond-swag-unveiling-the-profound-impact-of-community-engagement-on-my-journey-to-authorship-4ef9</link>
      <guid>https://dev.to/aws-builders/beyond-swag-unveiling-the-profound-impact-of-community-engagement-on-my-journey-to-authorship-4ef9</guid>
      <description>&lt;p&gt;When I was in school, I struggled to find a balance between my strong passion for science projects and my tendency to become bored owing to the lack of lab equipment. 2004 was the year when I made the transition to computer science and began coding. Fast forward to my time spent in college, where I and my friends started working as freelancers, although the level of community involvement was limited.&lt;/p&gt;

&lt;p&gt;Gaining an Understanding of the Power of Communities:&lt;br&gt;
My exploration into the Internet of Things began in 2015, when I discovered Hackster.io, where I began publishing articles and winning competitions. I learned from this experience that communities are not simply about giving away free stuff (swag); rather, they are about learning, sharing, and working together.&lt;/p&gt;

&lt;p&gt;AWS Community Builder Program: In 2021, I became a member of the AWS Community Builder program where my outlook was altered. Learning, practicing, asking questions, and sharing experiences were all stressed throughout the process. Through the use of LinkedIn as a venue for distributing my content, Packt Acquisition became interested in my work.&lt;/p&gt;

&lt;p&gt;An unanticipated book opportunity presented itself when Packt came us to express their interest in working together on a book titled "Arduino IoT Cloud for Developers." This was a surprise, but it was also exciting. The process of writing the book took a year, but it was satisfying.&lt;/p&gt;

&lt;p&gt;In conclusion, participating in communities is about more than just getting free stuff; it's also about building a network, honing talents, and finding chances that you would not have anticipated. Every stage of my path, from working as a sole coder to writing a book, has given me the opportunity to witness the transformational power of community involvement. The lesson is that even seemingly insignificant occurrences of learning, sharing, and working together can result in spectacular consequences. The journey is truly remarkable because it is not just about the concrete rewards; it is also about the intangible rewards.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>community</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AWS for WordPress: Getting starting with Light Sail, Cloud-front and Route 53 : Part-3</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Tue, 05 Dec 2023 16:36:29 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-3-21k8</link>
      <guid>https://dev.to/aws-builders/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-3-21k8</guid>
      <description>&lt;p&gt;Hello guys,&lt;/p&gt;

&lt;p&gt;Welcome back to the third and last episode of this series. In this article, we will setup the Lightsail distribution, which is actually a world-wide CDN service specially designed for web apps to provide a faster experience to website visitors. After distribution setup, we will update our domain records for Lightsail distribution.&lt;/p&gt;

&lt;p&gt;Click on the "&lt;strong&gt;Network&lt;/strong&gt;" menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--axwvUfOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxl8j7shqafbyuiag4dy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--axwvUfOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxl8j7shqafbyuiag4dy.png" alt="Image description" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now click on the "Create Distribution" button. Remember, before moving towards distribution setup, it's mandatory to assign static IP to your LightSail instance, as we did in Part 2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EfjuT3f0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxhzlaq1ipuw5hhole8h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EfjuT3f0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxhzlaq1ipuw5hhole8h.png" alt="Image description" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select origin from the drop-down menu as shown in the below screenshot, which means selecting your Lightsail instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3sn1Q2Az--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vdrtd2knly6in034cuoz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3sn1Q2Az--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vdrtd2knly6in034cuoz.png" alt="Image description" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By default, cache behavior is set to &lt;strong&gt;WordPress&lt;/strong&gt;, so you don't need to do anything, but if you are using any other app on Lightsail instead of WordPress, then choose this option wisely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WwVM2dZq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwztxc7bbljqw4upapk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WwVM2dZq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwztxc7bbljqw4upapk0.png" alt="Image description" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's time to select the distribution plan. Well, I am choosing the &lt;strong&gt;50GB/month&lt;/strong&gt; plan for testing purposes, and it's also free for one year, but you can choose the plan according to your traffic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EIysPDla--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avbaj3mffz6qnnutm6id.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EIysPDla--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/avbaj3mffz6qnnutm6id.png" alt="Image description" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the final step, you need to assign the name for your distribution and click on the "Create Distribution" button. It will take a little bit of time to create the distribution; just sit back and take a sip of coffee.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QRqaXx2C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gow49uo7unu3aaw3g19f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QRqaXx2C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gow49uo7unu3aaw3g19f.png" alt="Image description" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the successful creation of distribution, it's time to generate SSL certificates for distribution. Click on the "&lt;strong&gt;Custom Domains&lt;/strong&gt;" tab, and then click on "Create certificate**" It will show you the pop-up where you need to enter your certificate name and domain name. I added my domain, including &lt;a href="http://www.iotsnacks.com"&gt;www.iotsnacks.com&lt;/a&gt; and iotsnacks.com.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1cpoX6bh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wud74gz9j7vs3g976kz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1cpoX6bh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wud74gz9j7vs3g976kz2.png" alt="Image description" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will take some time, and later it will show you a validation error. Click on "Validation Details," and it will guide you to add CNAME records to your domain. So in our case, we are using Route 53, and we will add these verification CNAME records to Route 53. Later on, it will automatically verify the records.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KlOSMMrr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jp5s4sj8dbza0lq2zx59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KlOSMMrr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jp5s4sj8dbza0lq2zx59.png" alt="Image description" width="800" height="733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After domain verification, it will show you the "Attach certificate" option. Just click on that and attach the certificates to your distribution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DB-iyvhc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1srv2a4b29624nli2ad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DB-iyvhc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1srv2a4b29624nli2ad.png" alt="Image description" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T35_7lhu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mzfcuk0qmruen3mtetzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T35_7lhu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mzfcuk0qmruen3mtetzs.png" alt="Image description" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, in the final step, we need to route our domain traffic to this distribution. On the same page, at the end, you will see the URL of that distribution. Just copy the URL and navigate to Route 53.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JEi_2vmG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2s7bmna77ljoyw6ap55h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JEi_2vmG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2s7bmna77ljoyw6ap55h.png" alt="Image description" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Route 53, click on "Hosted Zones" and select your domain, then click on "Create Record," and you will see the page just like below. Follow the instructions as per the below image, and you are good to go with the record addition.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--frCQUMyY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mjsgutclgkg48sngs75i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--frCQUMyY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mjsgutclgkg48sngs75i.png" alt="Image description" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You have successfully deployed your WordPress website on AWS using Route 53+ Lightsail and Lightsail Distribution, also known as Cloud Front.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>AWS for WordPress: Getting starting with Light Sail, Cloud-front and Route 53 : Part-2</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Sun, 03 Dec 2023 19:35:16 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-2-19nf</link>
      <guid>https://dev.to/aws-builders/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-2-19nf</guid>
      <description>&lt;p&gt;Welcome back, guys, to Part #2. In this post, we will set up a Lightsail instance for WordPress. Type the Lightsial into the AWS console search bar and select the Lightsail, as shown in the below screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JAp2ajaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mnbypbolcamysgj6g3pg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JAp2ajaC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mnbypbolcamysgj6g3pg.png" alt="Image description" width="800" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see the new page on a separate tab. Just click on the "&lt;strong&gt;Create instance&lt;/strong&gt;"&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--61xAped9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1a6borq9cukr5s0oug64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--61xAped9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1a6borq9cukr5s0oug64.png" alt="Image description" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you will see the long configuration page for Lightsail. There are different options available, which I marked with numbers.&lt;/p&gt;

&lt;p&gt;1# Select the region where you want to deploy your instance. I am choosing &lt;strong&gt;Virginia, Zone A&lt;/strong&gt;.&lt;br&gt;
2# Select the OS, for WordPress Linux OS is the best option, but you can choose Windows according to your requirements. In my case, I am choosing &lt;strong&gt;Linux&lt;/strong&gt;.&lt;br&gt;
3# Select the application from the collection, but I am going to choose &lt;strong&gt;WordPress&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qwHq49dZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8eslt4j0d9ynbiv6xnnr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qwHq49dZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8eslt4j0d9ynbiv6xnnr.png" alt="Image description" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, scroll down the page, and it's time to select the instance type according to price or compute power depending upon your requirements.&lt;/p&gt;

&lt;p&gt;4# If you don't know the processing load, then I will recommend you choose the USD 5 instance, which offers 1GB of RAM, 2 V CPUs, including a 40 GB SSD, and 2 TB of bandwidth.&lt;br&gt;
5# Assign the name to the instance. It's a good option to assign your instance name according to your domain name.&lt;br&gt;
6# Finally, click on the "Create instance" button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vqFgoJi4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n5if9wlkrmxuwb7r6p4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vqFgoJi4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n5if9wlkrmxuwb7r6p4j.png" alt="Image description" width="800" height="843"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's time to take some coffee, as AWS takes a little time to create and make your instance live. Congratulations! Your instance is live after a few minutes, and now it's time to assign a static IP to your Lightsail instance, as it's required for cloudfront. Click on the "&lt;strong&gt;Networking&lt;/strong&gt;" link, which is marked in the below picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---N8TdtSR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ev7iri7ix4naxqey0hcu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---N8TdtSR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ev7iri7ix4naxqey0hcu.png" alt="Image description" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the "Create static IP" button, as shown in the below screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KIhgve1V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vk753i7k4neqiqrmypay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KIhgve1V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vk753i7k4neqiqrmypay.png" alt="Image description" width="800" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On this page, as shown in the below screenshot, you can select your IP location, but I didn't change it. Next,&amp;nbsp; you need to select your Lightsail instance to allot a static IP address, and in the last, assign the name to your static IP address. And in the end, click on "Create," and you are good to go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IzxBVtGw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l95nuoua8st7sinucv8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IzxBVtGw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l95nuoua8st7sinucv8d.png" alt="Image description" width="800" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! A static IP has been assigned to the Lightsail instance, as shown in the below screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KfZk0VMX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nv3tfylj7pja82lodcy5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KfZk0VMX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nv3tfylj7pja82lodcy5.png" alt="Image description" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once again, congratulations, guys. Your AWS Lightsail instance for WordPress is up and running, and we also assigned the static IP to that instance. In the next post, we will set up the cloudfront and distribution for our instance.&lt;/p&gt;

&lt;p&gt;In the next post you will learn how to setup the distribution for Lightsail instance. &lt;a href="https://dev.to/mafzal9/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-3-21k8"&gt;Click here to read Part#3&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>webdev</category>
      <category>aws</category>
      <category>freelance</category>
    </item>
    <item>
      <title>AWS for WordPress: Getting starting with Light Sail, Cloud-front and Route 53 : Part-1</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Sun, 03 Dec 2023 19:34:46 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-1-2m1l</link>
      <guid>https://dev.to/aws-builders/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-1-2m1l</guid>
      <description>&lt;p&gt;Hey everyone,&lt;/p&gt;

&lt;p&gt;I hope you all are fine. Sorry, I was busy writing my book. That's why I was unable to write some posts for my AWS community. But now I am free, and it's time to calibrate my free time with my AWS community. Oh, oops, if you are curious about my book, then just type "&lt;strong&gt;&lt;em&gt;Arduino IoT Cloud for Developers&lt;/em&gt;&lt;/strong&gt;" at Amazon and you will find the details.&lt;/p&gt;

&lt;p&gt;So coming to the point, on the coming Sunday, which will be the 10th of December 2023, I have my talk at WordCamp Lahore, where I am going to demonstrate how to use AWS for WordPress websites and e-commerce stores. That's why I made plans to write these articles that will help the event audience and lame excuse to talk to my community.&lt;/p&gt;

&lt;p&gt;Are you guys ready?&lt;/p&gt;

&lt;p&gt;So let's get started with the journey. OK, I have divided the content into three different posts to make the articles easier and more flexible for everyone.&lt;/p&gt;

&lt;p&gt;Part 1: In this post (current), we will set up Route 53 for our domain.&lt;br&gt;
Part 2: In the second part, we will setup the AWS Lightsail instance for WordPress.&lt;br&gt;
Part 3: In the third part, we will setup the AWS Lightsail Distribution/Cloud Front and configure the routing records at Route 53.&lt;/p&gt;

&lt;p&gt;Before starting the tutorial here, you need to understand why we need Route 53. Actually, Route 53 is a managed DNS service for domain names. You can directly use Lightsail with your custom DNS service provider, but I will recommend you use Route 53 as it will help you in the future if you want to add more AWS services for your organization under the same domain. which will make it easy for everyone to manage all the stuff under one roof.&lt;/p&gt;

&lt;p&gt;Login to the AWS Console, type Route 53 in the console search, and select the Route 53 service. Now click on the "&lt;strong&gt;Hosted Zones&lt;/strong&gt;," which are marked in the picture and located at the left side bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BBoW_W7D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vi9qj0cirbtz86yg14r7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BBoW_W7D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vi9qj0cirbtz86yg14r7.png" alt="Image description" width="508" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After reaching the Hosted Zones page, click on the "&lt;strong&gt;Create hosted zone&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jEkHGB19--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r5rg72hxiusis8q0rrc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jEkHGB19--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r5rg72hxiusis8q0rrc0.png" alt="Image description" width="800" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you need to provide a domain name, and we are good to go and click on the "&lt;strong&gt;Create hosted zone&lt;/strong&gt;" button.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8m9cg6HW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qcjgiez3nyeo1sg2knj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8m9cg6HW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qcjgiez3nyeo1sg2knj.png" alt="Image description" width="800" height="805"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! nameservers have been successfully created for your domain, and it is time to point your domain to these nameservers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xSFxfUqI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6bbxp6js7lg43lwfqsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xSFxfUqI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y6bbxp6js7lg43lwfqsp.png" alt="Image description" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below, I just updated my domain nameservers to Route 53 nameservers. You guys can update your domain nameservers by logging into your domain registrar panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OGnw1Ft5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rh8rxtclsvqkwv2em9bn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OGnw1Ft5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rh8rxtclsvqkwv2em9bn.png" alt="Image description" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next part of the post, we will set up the Lightsail instance for WordPress. &lt;a href="https://dev.to/aws-builders/aws-for-wordpress-getting-starting-with-light-sail-cloud-front-and-route-53-part-2-19nf"&gt;Click here to read Part 2&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>aws</category>
      <category>webdev</category>
      <category>freelance</category>
    </item>
    <item>
      <title>Welcome to Google Analytics 4</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Wed, 03 Aug 2022 17:35:00 +0000</pubDate>
      <link>https://dev.to/mafzal9/welcome-to-google-analytics-4-35fi</link>
      <guid>https://dev.to/mafzal9/welcome-to-google-analytics-4-35fi</guid>
      <description>&lt;p&gt;Hello everyone welcome to my new article which is totally different from other articles that mean i am not going to talk about any development but going to talk about an awesome tool which will guide you in your development &amp;amp; growth. so guys ready for article? lets go :)&lt;/p&gt;

&lt;p&gt;In this digital world we have lot of different products and services which work in combination but due to job trades we left or we put the stuff on others shoulders. well in this article i am going to talk about a very fantastic tool "Google Analytics" .&lt;/p&gt;

&lt;p&gt;There is a myth that Google Analytics is only used by Digital Marketers which is totally wrong actually this is the tool which is for everyone if you have your online presence like your personal website/ business website/ or e-commerce store and etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So Let's come to the Point what is Google Analytics?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google Analytics is a service by integrating into your website you can get data about your visitors, their explorations on website, their session duration, which technology they are using, from which region country/state/city they are coming and lot of other stuff. so these things are very important for digital marketers with respect to marketing point of view but it's also important for main stake holders to learn about Google Analytics to get an idea about their visitors demands and trends as well as if you are an early stage startup founder then defiantly it's your main eye to get succeed in this digital world which will help you to take decisions according to your visitors requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's new in Google Analytics 4?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Totally New interface as compared to Universal Analytics.&lt;/li&gt;
&lt;li&gt;In GA4 all the things are considered as Event instead of considering different stuff like Page View, Users and etc.&lt;/li&gt;
&lt;li&gt;New style of View Reports&lt;/li&gt;
&lt;li&gt;Compact E-Commerce tracking Reports&lt;/li&gt;
&lt;li&gt;Cross Platform Tracking with different data streams which simplified to monitor the traffic of different platforms at one place.&lt;/li&gt;
&lt;li&gt;Support of BigQuery to fetch data according to requirements.&lt;/li&gt;
&lt;li&gt;Debugging is an awesome feature in GA4 which enables you to debug your events,visit very professionally.&lt;/li&gt;
&lt;li&gt;Advance SPAM data prevention options.&lt;/li&gt;
&lt;li&gt;Advance Reporting as well us their is option to create custom reports.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How to use Google Analytics in website?&lt;/strong&gt;&lt;br&gt;
1-It's very simple just navigate to &lt;a href="https://analytics.google.com"&gt;Google Analytics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2-Signup to Google analytics with you google account.&lt;/p&gt;

&lt;p&gt;3-Next it will take you to your website setup where you need to just put your website name. after that it will show you JavaScript code snippet.&lt;/p&gt;

&lt;p&gt;4-Copy that JavaScript Code Snippet which is provided by Google Analytics and put into your website head. If you are using WordPress then use "Insert Header &amp;amp; Footer Plugin".&lt;/p&gt;

&lt;p&gt;If you want to learn more in depth about Google Analytics 4 &amp;amp; GTM then this Udemy course is for you &lt;a href="https://www.udemy.com/course/master-google-analytics-4-ga4-gtm-in-2022/?referralCode=53AEE71075A00E41B253"&gt;Master Google Analytics 4 (GA4) &amp;amp; GTM in 2022&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This post includes affiliate links; I may receive compensation if you purchase products or services from the links provided in this article.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>google</category>
      <category>analytics</category>
      <category>webdev</category>
      <category>wordpress</category>
    </item>
    <item>
      <title>Getting started with Bootstrap 5</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Tue, 02 Aug 2022 17:40:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/getting-started-with-bootstrap-5-5db</link>
      <guid>https://dev.to/aws-builders/getting-started-with-bootstrap-5-5db</guid>
      <description>&lt;p&gt;&lt;strong&gt;What is Responsive Design &amp;amp; Bootstrap?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In early days we have very basic infrastructure of website services and for development HTML is enough but with the passage of time demand of web services increased and step by step different technologies came into existence to fulfill the growing need such as CSS, JavaScript and dynamic languages such as PHP, ASP.Net, Java and etc.&lt;/p&gt;

&lt;p&gt;But the real evolution begins with the advancement of mobile technology, then the demand of responsive web design grows instantly. At that time CSS media queries  are introduced to handle the different screen size issues but front end development becomes very complex as every person have it's own nature to write the code and have it's own set of screens for testing. Then Bootstrap come into ground with revolutionary responsive model which is called grid system.&lt;/p&gt;

&lt;p&gt;Bootstrap is an opensource CSS &amp;amp; JS Framework for responsive website development. Bootstrap works on the model of grid system and they have defined generic breakpoints with respect to different screen sizes such as Extra Small, Small, Medium, Large, Extra Large, Extra Extra Large, Framework is packed with custom CSS classes which provides very fast and effective working model. Developers are required to just remember the classes and get rid of long CSS properties.&lt;/p&gt;

&lt;p&gt;Bootstrap saves the time &amp;amp; cost in development of responsive website design as well as provide very beautiful responsive components such as Navigation Bar, Cards, Carousal, Forms and much more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's new in Bootstrap 5?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Initially Bootstrap has been launched in Aug, 2011 with version 1.x and later they released different versions like 2.x, 3.x and 4.x is a version which is mostly used by developers. Recently they launched the new version of Bootstrap which is Bootstrap 5 and contains new classes for advance responsive website design.&lt;/p&gt;

&lt;p&gt;In bootstrap 5 they have updated the logo, New Offcanvas Component, New accordion and they have created very awesome experience for forms such as floating labels, validations, Simplified Layouts and etc.&lt;/p&gt;

&lt;p&gt;Previous versions of Bootstrap didn't support RTL(Right-to-Left) Content which is very important features for Arabic,Urdu, Persian websites. Now developers can easily build websites for those languages which are RTL based.&lt;/p&gt;

&lt;p&gt;In Boostrap 5 they added many classes and removed some old classes of version 4 so it's recommend to study the documentation of Version 5 before migrating your older version to newest version. complete upgrade documentation is available at &lt;a href="https://blog.getbootstrap.com/2021/05/05/bootstrap-5/"&gt;https://blog.getbootstrap.com/2021/05/05/bootstrap-5/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn Bootstrap 5&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Bootstrap is famous due to it's simplicity, easy working style, extensibility but this is all due to well documentation, strong community. so if you are new to responsive website design then get started with there &lt;a href="https://getbootstrap.com/docs/5.2/getting-started/introduction/"&gt;documentation&lt;/a&gt;   and i also created very detailed course at Udemy &lt;a href="https://www.udemy.com/course/mastering-bootstrap-5-complete-guide-step-by-step-2022/?referralCode=A02AAAA3B08A1FAF9B42"&gt;Mastering Bootstrap 5 - Complete Guide Step by Step 2022&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This post includes affiliate links; I may receive compensation if you purchase products or services from the links provided in this article.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>bootstrap</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Setting up Static Website on AWS S3</title>
      <dc:creator>Muhammad Afzal</dc:creator>
      <pubDate>Mon, 28 Mar 2022 19:19:13 +0000</pubDate>
      <link>https://dev.to/aws-builders/setting-up-static-website-on-aws-s3-18oh</link>
      <guid>https://dev.to/aws-builders/setting-up-static-website-on-aws-s3-18oh</guid>
      <description>&lt;p&gt;Hello Geeks,&lt;/p&gt;

&lt;p&gt;You gotta an overview of article by the title. It's 2022 and world is using CMS System for their websites or custom developed dynamic websites but still there are lot of geeks who have static websites and i am one of them. Back in 2018 i develeoped a javascript enabled web based MQTT Client for MQTT Broker testing and debugging. For the hosting of &lt;a href="http://mqtt.run" rel="noopener noreferrer"&gt;http://mqtt.run&lt;/a&gt; i used lot of different web hosting services but after becoming AWS Community Builder i started reviewing the services related to cloud storage, Already i am using AWS Lightsail and CloudFront for my E-Commerce &amp;amp; Tutorial website &lt;a href="https://phpdocs.com" rel="noopener noreferrer"&gt;https://phpdocs.com&lt;/a&gt; but this time when i studied about S3 i made a plan to host one of my static website on S3 to get the taste of cloud for static website. &lt;/p&gt;

&lt;p&gt;So if we generally talk about AWS S3 it's a storage services to host docs, images, videos or what ever you want to host on it. S3 is a reasonable and good solution in terms of Space, Bandwidth and region availability, so they are also providing option to host static website. Right now i am going to explore how to host static website on S3 but in future articles i will share how to host video content on S3 for educational website.&lt;br&gt;
**&lt;/p&gt;

&lt;p&gt;Firstly login into your AWS Console &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;https://aws.amazon.com/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;u&gt;Step#1&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After login type S3 in the search and click on S3 Service.&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fnxntp7w2rjoqrhl37ijf.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.amazonaws.com%2Fuploads%2Farticles%2Fnxntp7w2rjoqrhl37ijf.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Step#2&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
Click on &lt;strong&gt;&lt;u&gt;Create Bucket&lt;/u&gt;&lt;/strong&gt; Button.&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.amazonaws.com%2Fuploads%2Farticles%2Frh2bu5lqjguh8lzkbzh0.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.amazonaws.com%2Fuploads%2Farticles%2Frh2bu5lqjguh8lzkbzh0.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Step#3&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After clicking on Bucket you will see a very long tail form but you don't need to worry as all are simple options.&lt;/p&gt;

&lt;p&gt;1-Firstly enter the full domain name under bucket name in my scenario i have &lt;a href="http://www.mqtt.run" rel="noopener noreferrer"&gt;www.mqtt.run&lt;/a&gt; domain name.&lt;/p&gt;

&lt;p&gt;2-Select the region which is nearest to you, it will give  awesome browsing experience to your users. i am choosing Singapore as it's near to my region.&lt;/p&gt;

&lt;p&gt;3-if you want to Copy settings from existing bucket then choose the bucket else don't touch it.&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.amazonaws.com%2Fuploads%2Farticles%2Fduz6ucaqi94t7k1ou5mc.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.amazonaws.com%2Fuploads%2Farticles%2Fduz6ucaqi94t7k1ou5mc.png" alt=" " width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4-Choose ACL Disabled Under "Object Ownership".&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.amazonaws.com%2Fuploads%2Farticles%2F7rp273jlcxblyhabjjcv.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.amazonaws.com%2Fuploads%2Farticles%2F7rp273jlcxblyhabjjcv.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5- Uncheck the "Block all public access" Under "Block Public Access settings for this bucket" and click on checkbox "I acknowledge that the current settings might result in this bucket and the objects within becoming public."&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.amazonaws.com%2Fuploads%2Farticles%2F1ci2lhefwv4qc7ugbthd.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.amazonaws.com%2Fuploads%2Farticles%2F1ci2lhefwv4qc7ugbthd.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6-Leave the other configurations as it is and click on "Create Bucket" Button&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.amazonaws.com%2Fuploads%2Farticles%2Fi454vq6hah5s226pzbvj.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.amazonaws.com%2Fuploads%2Farticles%2Fi454vq6hah5s226pzbvj.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7-after that you will see your buckets like that. now click on bucket for further configuration.&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.amazonaws.com%2Fuploads%2Farticles%2F3n37fma0lgo1wm8tevbj.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.amazonaws.com%2Fuploads%2Farticles%2F3n37fma0lgo1wm8tevbj.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8-Under Objects tabs click on Upload and upload your files and folders. don't upload zip file as there is no option to extract the zip files. you need to upload files and folder manually. the good thing is that just select the folder and it will take care of all files and folder inside the selected folder.&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.amazonaws.com%2Fuploads%2Farticles%2Fx5mrni2xz38oqpa8z9zq.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.amazonaws.com%2Fuploads%2Farticles%2Fx5mrni2xz38oqpa8z9zq.png" alt=" " width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;9-After that click on Properties tab and scroll down the page to bottom and find the section "Static website hosting" and click on Edit as we need to enable website feature on our S3 Bucket.&lt;/p&gt;

&lt;p&gt;10-Select Enable under Static website hosting and Select "Host a static website" under Hosting type. provide Index document which is usually "index.html" or "default.html" but in my case it's "index.html".&lt;/p&gt;

&lt;p&gt;11- After selecting all these options just save the changes.&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.amazonaws.com%2Fuploads%2Farticles%2Fbxrdkwjihjbfgd3autrt.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.amazonaws.com%2Fuploads%2Farticles%2Fbxrdkwjihjbfgd3autrt.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;12- After Changes you will see the URL of your static website.&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.amazonaws.com%2Fuploads%2Farticles%2Fjdrfsp8jszh0zpwvte4g.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.amazonaws.com%2Fuploads%2Farticles%2Fjdrfsp8jszh0zpwvte4g.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But when you click on that url you will get the file permission error as because we didn't set any permission policy on our bucket.&lt;/p&gt;

&lt;p&gt;13- Click on "Permission" Tab, Scroll the page and find "Bucket policy" and click on "Edit"&lt;/p&gt;

&lt;p&gt;14-Copy the below Policy just write your bucket name instead of &lt;a href="http://www.example.com" rel="noopener noreferrer"&gt;www.example.com&lt;/a&gt; and click on save changes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{&lt;br&gt;
    "Version": "2012-10-17",&lt;br&gt;
    "Statement": [&lt;br&gt;
        {&lt;br&gt;
            "Sid": "PublicReadGetObject",&lt;br&gt;
            "Effect": "Allow",&lt;br&gt;
            "Principal": "*",&lt;br&gt;
            "Action": "s3:GetObject",&lt;br&gt;
            "Resource": "arn:aws:s3:::www.example.com/*"&lt;br&gt;
        }&lt;br&gt;
    ]&lt;br&gt;
}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Again open the URL and it will work fine Hurry Congrats. Next you need to point Your domain to S3 Bucket URL. Either you can point your domain cname records to S3 Static website URL or you can use AWS Route 53 to setup nameservers for your domain.&lt;/p&gt;

&lt;p&gt;Well i am asuming that you don't have access to create cname records in your domain panel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Step#4&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1- Click on Top search bar and type Route 53 and click on Route 53 below from the suggestions.&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.amazonaws.com%2Fuploads%2Farticles%2Fq3014dp695eo3oggugpq.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.amazonaws.com%2Fuploads%2Farticles%2Fq3014dp695eo3oggugpq.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2- Click on Hosted Zone.&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.amazonaws.com%2Fuploads%2Farticles%2Ft85agvv3kok4moivpzd8.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.amazonaws.com%2Fuploads%2Farticles%2Ft85agvv3kok4moivpzd8.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3- Click on "Create Hosted Zone".&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.amazonaws.com%2Fuploads%2Farticles%2Fk6v2zcntnlj0ejqpty2a.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.amazonaws.com%2Fuploads%2Farticles%2Fk6v2zcntnlj0ejqpty2a.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4-Enter Domain name and leave the other settings.&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.amazonaws.com%2Fuploads%2Farticles%2Fqwk4q25newlp51x3wmlb.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.amazonaws.com%2Fuploads%2Farticles%2Fqwk4q25newlp51x3wmlb.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5- Click on "Create Hosted Zone"&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fucyh9ytket6f2wo84vg1.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.amazonaws.com%2Fuploads%2Farticles%2Fucyh9ytket6f2wo84vg1.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that you will get your zone listed.&lt;br&gt;
6- Click on your Domain.&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.amazonaws.com%2Fuploads%2Farticles%2Foydb9ql16r8lc0k4va6a.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.amazonaws.com%2Fuploads%2Farticles%2Foydb9ql16r8lc0k4va6a.png" alt=" " width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;7- Copy Nameservers and set to domain in domain panel.&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.amazonaws.com%2Fuploads%2Farticles%2Fm4pi01gk35vrdmha5jq8.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.amazonaws.com%2Fuploads%2Farticles%2Fm4pi01gk35vrdmha5jq8.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8- After setting your domain Nameservers click on "Create Record"&lt;br&gt;
Here select CNAME under Record Type and Enter S3 Website URL under Value textarea and click on "Create Record" Button.&lt;/p&gt;

&lt;p&gt;It will take some time to propagate the DNS Settings, later you can browse your website by directly type URL instead of long S3 URL.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>webdev</category>
      <category>website</category>
    </item>
  </channel>
</rss>
