<?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: Preetkamal Singh</title>
    <description>The latest articles on DEV Community by Preetkamal Singh (@preetsingh).</description>
    <link>https://dev.to/preetsingh</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%2F2313493%2F57f4b1fe-f9b4-4b38-b1e6-c0cc357e91fb.png</url>
      <title>DEV Community: Preetkamal Singh</title>
      <link>https://dev.to/preetsingh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/preetsingh"/>
    <language>en</language>
    <item>
      <title>Why your favicon doesn't show in Google Search — and everything else that silently broke after my Next.js deploy</title>
      <dc:creator>Preetkamal Singh</dc:creator>
      <pubDate>Sun, 05 Jul 2026 06:51:53 +0000</pubDate>
      <link>https://dev.to/preetsingh/why-your-favicon-doesnt-show-in-google-search-and-everything-else-that-silently-broke-after-my-5ee2</link>
      <guid>https://dev.to/preetsingh/why-your-favicon-doesnt-show-in-google-search-and-everything-else-that-silently-broke-after-my-5ee2</guid>
      <description>&lt;p&gt;My deploy was green. The site worked. The favicon showed in the browser tab. Done, right?&lt;/p&gt;

&lt;p&gt;Then over the next weeks I discovered, one by one: Google showed a gray globe instead of my logo, my link previews rendered differently on every platform (broken image on Facebook and Discord, fine on Twitter), and Safari on iPhone was showing the &lt;em&gt;Vercel triangle&lt;/em&gt; in my tab strip — a logo I never put anywhere.&lt;/p&gt;

&lt;p&gt;None of these threw an error. Nothing failed in CI. Everything just silently didn't work. Here is every cause I found debugging it on my production app (&lt;a href="https://jobcost.app" rel="noopener noreferrer"&gt;jobcost.app&lt;/a&gt;), in the order you should check them, with the exact Next.js (App Router) fix for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Google ignores favicons that aren't a 48px multiple
&lt;/h2&gt;

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

&lt;p&gt;Google requires the search-result favicon to be a &lt;strong&gt;square, and a multiple of 48px&lt;/strong&gt; — 48×48, 96×96, 144×144 — or an SVG. The classic 16×16/32×32 &lt;code&gt;favicon.ico&lt;/code&gt; renders fine in the browser tab and gets silently ignored by Google. The tab tells you nothing.&lt;/p&gt;

&lt;p&gt;App Router fix — use the file convention, no manual tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/
  icon.png        // square PNG, 96x96 or larger — Next.js generates the &amp;lt;link&amp;gt; tag
  apple-icon.png  // 180x180 — you need this one more than you think (see #2)
  favicon.ico     // keep for legacy browsers — but read #2 first
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. The Vercel triangle you never added: create-next-app's default favicon
&lt;/h2&gt;

&lt;p&gt;This one hurt. Safari on my iPhone showed the Vercel logo in the tab strip for my own product. Clearing history did nothing.&lt;/p&gt;

&lt;p&gt;Cause: &lt;code&gt;create-next-app&lt;/code&gt; ships a default &lt;code&gt;favicon.ico&lt;/code&gt; (the Vercel/Next triangle). Depending on your version it lives in &lt;code&gt;app/&lt;/code&gt; or &lt;code&gt;public/&lt;/code&gt; — and if you replaced one location, the template file can survive in the other. &lt;code&gt;public/favicon.ico&lt;/code&gt; will happily keep serving the triangle after you've added a beautiful &lt;code&gt;app/icon.png&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Three-part fix:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Search your repo for every &lt;code&gt;favicon.ico&lt;/code&gt;&lt;/strong&gt; — check &lt;code&gt;public/&lt;/code&gt; specifically. Delete the template one; keep exactly one, yours, in &lt;code&gt;app/favicon.ico&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add &lt;code&gt;app/apple-icon.png&lt;/code&gt; (180×180).&lt;/strong&gt; Safari prefers the apple touch icon for tab strips and bookmarks; without it, it falls back to that stale .ico.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know that Safari caches favicons separately from history.&lt;/strong&gt; "Clear History" does not clear it. Settings → Safari → Advanced → Website Data → delete your site's entry. And tabs already open keep the icon from when they loaded — test with a &lt;em&gt;fresh&lt;/em&gt; tab, or you'll chase a ghost like I did.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verify like an engineer, not a browser-refresher: open &lt;code&gt;yourdomain.com/favicon.ico&lt;/code&gt; and &lt;code&gt;/apple-icon.png&lt;/code&gt; directly in a private tab. What those URLs serve is the truth; everything else is cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. You have twitter:image but no og:image
&lt;/h2&gt;

&lt;p&gt;My link previews were inconsistent: fine on X, broken image everywhere else. Cause: my head had &lt;code&gt;twitter:image&lt;/code&gt; but &lt;strong&gt;no &lt;code&gt;og:image&lt;/code&gt;&lt;/strong&gt;. X reads its own tag; Facebook, WhatsApp, LinkedIn, Discord, Telegram, iMessage all want &lt;code&gt;og:image&lt;/code&gt;. Miss it and every platform except X shows a broken card.&lt;/p&gt;

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

&lt;p&gt;The Facebook Sharing Debugger even warns you — &lt;em&gt;"Inferred Property: the og:image property should be explicitly provided"&lt;/em&gt; — but only if you think to look.&lt;/p&gt;

&lt;p&gt;Related trap: if you have &lt;em&gt;both&lt;/em&gt; old manual &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tags (from a Head component or next-seo) &lt;em&gt;and&lt;/em&gt; the new &lt;code&gt;metadata&lt;/code&gt; export, they fight — I ended up with &lt;code&gt;og:image content=""&lt;/code&gt; rendering empty. One source of truth only. Delete every manual OG tag and use the export:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/layout.tsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;metadataBase&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;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// required to resolve relative image paths&lt;/span&gt;
  &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your Title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Your description.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/og-image.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;630&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;twitter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;summary_large_image&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/og-image.png&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify in &lt;code&gt;view-source:&lt;/code&gt; — exactly one &lt;code&gt;og:image&lt;/code&gt; tag, absolute URL inside. Only after the raw HTML is right do the checkers mean anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Your fix is deployed — but your CDN is serving the old version
&lt;/h2&gt;

&lt;p&gt;This is the one that cost me the most hours: I had already fixed the meta tags, but Cloudflare kept serving the cached old HTML and images. Every checker kept "proving" my fix didn't work.&lt;/p&gt;

&lt;p&gt;If you're behind Cloudflare (or any CDN): after deploying meta/icon changes, &lt;strong&gt;purge the cache&lt;/strong&gt; for the affected paths (or purge everything). Then — separately — make Facebook re-fetch: Sharing Debugger → your URL → &lt;strong&gt;Scrape Again&lt;/strong&gt;. Facebook holds its own cache of your old broken card and will show it for weeks otherwise.&lt;/p&gt;

&lt;p&gt;Debugging order that saves your sanity: raw &lt;code&gt;view-source&lt;/code&gt; → direct asset URLs in a private tab → purge CDN → re-scrape checkers. Truth flows in that direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. robots.txt is silently blocking your icon
&lt;/h2&gt;

&lt;p&gt;Google fetches your favicon with a crawler. If &lt;code&gt;robots.txt&lt;/code&gt; blocks the icon's path — or a catch-all rule catches the &lt;code&gt;/_next/&lt;/code&gt; asset path — Google gives up with no warning anywhere. Check &lt;code&gt;yourdomain.com/robots.txt&lt;/code&gt; in production and confirm what &lt;code&gt;app/robots.ts&lt;/code&gt; actually outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Your homepage isn't indexed yet
&lt;/h2&gt;

&lt;p&gt;Google only shows a favicon for sites whose homepage it has indexed. Fresh domain, fresh deploy = no index = gray globe regardless of a perfect setup. Search Console → URL Inspection → homepage → &lt;strong&gt;Request Indexing&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Everything is right — Google is just slow
&lt;/h2&gt;

&lt;p&gt;Even with all of the above correct, Google can take &lt;strong&gt;days to weeks&lt;/strong&gt; to fetch and display a new favicon, and there is no "refresh favicon" button. Requesting reindexing nudges it; after that it's a queue. Sometimes the gray globe isn't a bug — it's a waiting room.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The pattern across all seven:&lt;/strong&gt; every one of these failures is silent. Green deploy, working tab, zero errors — and broken visibility that you discover by accident weeks later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The full post-deploy checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Favicon: square, 48px-multiple, stable URL, not robots-blocked&lt;/li&gt;
&lt;li&gt;Template &lt;code&gt;favicon.ico&lt;/code&gt; deleted from &lt;code&gt;public/&lt;/code&gt; AND &lt;code&gt;app/&lt;/code&gt; — yours in exactly one place&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apple-icon.png&lt;/code&gt; 180×180 exists&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;og:image&lt;/code&gt; present (not just twitter:image), absolute URL, 1200×630, loads with 200&lt;/li&gt;
&lt;li&gt;Exactly one set of OG tags in view-source — no duplicates fighting&lt;/li&gt;
&lt;li&gt;CDN purged after every meta/icon change; Facebook re-scraped&lt;/li&gt;
&lt;li&gt;Sitemap present and submitted; robots.txt allows what you think&lt;/li&gt;
&lt;li&gt;Canonical points at the right domain; homepage indexing requested&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;I'm building a tool that checks all of this in one shot&lt;/strong&gt; — paste your URL, get every silent post-deploy failure flagged with the exact Next.js fix. Free when it launches. &lt;a href="https://deploycheck-pink.vercel.app/" rel="noopener noreferrer"&gt;Leave your email here and I'll send it to you →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by a dev who stared at a gray globe, a broken preview card, and a Vercel triangle he never asked for. If this saved you that time, the signup genuinely helps me.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>seo</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>City Simulation with LLMs — Predicting Traffic &amp; Generating Natural-Language Reports</title>
      <dc:creator>Preetkamal Singh</dc:creator>
      <pubDate>Wed, 17 Sep 2025 08:42:10 +0000</pubDate>
      <link>https://dev.to/preetsingh/city-simulation-with-llms-predicting-traffic-generating-natural-language-3f4d</link>
      <guid>https://dev.to/preetsingh/city-simulation-with-llms-predicting-traffic-generating-natural-language-3f4d</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I built a city traffic simulation that ingests sensor data, predicts congestion, and uses an LLM to produce human-readable incident reports.  &lt;/p&gt;

&lt;p&gt;Live demo:&lt;a href="https://vercel.com/kamalpannus-projects/trafficpredictorfrontend" rel="noopener noreferrer"&gt;https://vercel.com/kamalpannus-projects/trafficpredictorfrontend&lt;/a&gt;  | Code: &lt;a href="https://github.com/Kamalpannu/trafficPredictor-Backend" rel="noopener noreferrer"&gt;https://github.com/Kamalpannu/trafficPredictor-Backend&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Kamalpannu/trafficpredictorfrontend" rel="noopener noreferrer"&gt;https://github.com/Kamalpannu/trafficpredictorfrontend&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;City operations teams need quick summaries of traffic hotspots from noisy sensor streams. Raw numbers are hard to scan under time pressure — so I built a system that predicts traffic issues and auto-generates plain-English reports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data ingestion:&lt;/strong&gt; simulated traffic sensors → time series store
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prediction service:&lt;/strong&gt; Python model (simple regression + heuristic)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM service:&lt;/strong&gt; LangChain wrapping an LLM to summarize predictions into reports
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React app for dashboards and report viewer
&lt;/li&gt;
&lt;li&gt;Dockerized and deployed via CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key implementation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
python
from fastapi import FastAPI
from pydantic import BaseModel
from langchain import OpenAI, LLMChain, PromptTemplate

app = FastAPI()
llm = OpenAI(api_key="YOUR_KEY", temperature=0.2)
prompt = PromptTemplate(
    input_variables=["summary"],
    template="You are a city ops assistant. Given this summary: {summary}\nWrite a 3-sentence incident report with suggested actions."
)
chain = LLMChain(llm=llm, prompt=prompt)

class Payload(BaseModel):
    summary: str

@app.post("/report")
async def report(payload: Payload):
    text = chain.run(payload.summary)
    return {"report": text}

Note: replace YOUR_KEY with your environment variable or secrets management.

What I learned

LLMs are great at turning numeric summaries into useful prose, but they require clear prompts and guardrails.

Keep the LLM step after deterministic prediction — don’t let it invent numbers.

Results

Generated concise reports that a non-technical operator can act on.

Demo and sample reports: see https://github.com/Kamalpannu/trafficPredictor-Backend
https://github.com/Kamalpannu/trafficpredictorfrontend

Full source code and deployment steps: https://vercel.com/kamalpannus-projects/trafficpredictorfrontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>langchain</category>
      <category>fastapi</category>
      <category>python</category>
    </item>
  </channel>
</rss>
