<?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: Ryan VerWey</title>
    <description>The latest articles on DEV Community by Ryan VerWey (@rverwey).</description>
    <link>https://dev.to/rverwey</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%2F1213395%2Fb0a67ef6-3d3c-41a1-b327-06e902153dc4.png</url>
      <title>DEV Community: Ryan VerWey</title>
      <link>https://dev.to/rverwey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rverwey"/>
    <language>en</language>
    <item>
      <title>The Decision Tax: When More Options Make an Interface Worse</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 08 Sep 2026 14:34:44 +0000</pubDate>
      <link>https://dev.to/rverwey/the-decision-tax-when-more-options-make-an-interface-worse-2mn</link>
      <guid>https://dev.to/rverwey/the-decision-tax-when-more-options-make-an-interface-worse-2mn</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.ryanverwey.dev/blog/the-decision-tax-choice-overload-ui" rel="noopener noreferrer"&gt;ryanverwey.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Choice overload is not the presence of many options. It is the point where an interface asks a person to do more comparison work than the decision feels worth.&lt;/p&gt;

&lt;p&gt;That distinction matters. A catalog with 10,000 products can feel manageable when search, filters, categories, recommendations, and comparison tools reduce the active decision to a useful set. A pricing page with four plans can feel overwhelming when the names are vague, features are inconsistent, and every card claims to be the best value.&lt;/p&gt;

&lt;p&gt;The design problem is not simply quantity. It is &lt;strong&gt;decision work&lt;/strong&gt;: how much effort users must spend understanding the choice, comparing alternatives, predicting consequences, and feeling confident enough to act.&lt;/p&gt;

&lt;p&gt;I call that accumulated effort the &lt;strong&gt;decision tax&lt;/strong&gt;. Every option adds potential value, but it can also add discovery, comparison, uncertainty, and regret. Good choice architecture preserves meaningful agency while reducing the tax required to use it.&lt;/p&gt;

&lt;p&gt;This second entry in my &lt;strong&gt;Applied Design Theory&lt;/strong&gt; series explains when choice overload is likely, why it is related to but different from Hick's Law, and how I use the SCOPE review to design better pricing pages, filters, onboarding flows, settings, and product selections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choice Overload Is a Mismatch, Not a Number
&lt;/h2&gt;

&lt;p&gt;Choice is usually valuable. It lets people express preferences, adapt a product to their situation, and avoid being forced into an unsuitable default. Removing all choice is not simplicity. It is control taken away from the user.&lt;/p&gt;

&lt;p&gt;Overload begins when the demands of the decision exceed the support provided by the interface. The same set of options can be easy for one person and exhausting for another because the user, task, consequences, and presentation have changed.&lt;/p&gt;

&lt;p&gt;Consider three people choosing a camera:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A professional photographer arrives with a specific mount, sensor requirement, and budget. A large catalog helps because their preferences are already formed.&lt;/li&gt;
&lt;li&gt;A first-time buyer knows they want better family photos but does not understand lenses, sensor formats, or stabilization. The same catalog creates a vocabulary problem before it creates a product decision.&lt;/li&gt;
&lt;li&gt;A traveler needs a replacement before a flight. Even with strong product knowledge, time pressure makes a large comparison set expensive.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The number of cameras did not change. The decision did.&lt;/p&gt;

&lt;p&gt;This is why rules such as "never show more than seven options" are attractive and unreliable. They convert a contextual design problem into an easy checklist. The interface may pass the checklist while leaving the actual work untouched.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fedse8vwqhwtr9m3b4qal.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fedse8vwqhwtr9m3b4qal.webp" alt="A conceptual curve showing that choice overload depends on option complexity, task difficulty, preference uncertainty, and the user's decision goal rather than a universal option count." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The overload threshold moves with the context. More options can improve fit until comparison cost and uncertainty begin to reduce confidence.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Famous Jam Study Actually Tells Us
&lt;/h2&gt;

&lt;p&gt;The most repeated choice-overload story comes from Sheena Iyengar and Mark Lepper's 2000 paper, &lt;a href="https://doi.org/10.1037/0022-3514.79.6.995" rel="noopener noreferrer"&gt;&lt;em&gt;When Choice Is Demotivating&lt;/em&gt;&lt;/a&gt;. In the field experiment, shoppers encountered a display of either 24 jams or six. The larger display attracted more attention, but nearly 30 percent of people exposed to the smaller set purchased a jar, compared with about 3 percent in the larger-set condition.&lt;/p&gt;

&lt;p&gt;The paper included two additional experiments. Students were more likely to complete an optional essay when choosing from six topics instead of 30, and participants choosing chocolates from a smaller assortment reported better experiences after the decision. Together, the studies challenged the assumption that more choice always produces more motivation and satisfaction.&lt;/p&gt;

&lt;p&gt;The useful lesson is not that six is a perfect interface number. Jam samples, essay prompts, and chocolates share particular conditions: options are similar, the ideal choice is uncertain, comparison consumes time, and choosing the wrong item is easy to imagine after the fact.&lt;/p&gt;

&lt;p&gt;The result is also a warning about product metrics. The large display won attention while the small display won purchasing. An interface can look engaging at the top of a funnel while making commitment harder at the bottom. Counting impressions, card opens, or time on page without measuring completion can reward the very friction the product should remove.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Research Does Not Support a Universal Limit
&lt;/h2&gt;

&lt;p&gt;Choice overload became a popular design explanation because it feels immediately true. Anyone who has stared at a wall of nearly identical televisions or compared a dozen software plans recognizes the experience. Research after the original studies, however, makes the conclusion more precise.&lt;/p&gt;

&lt;p&gt;Scheibehenne, Greifeneder, and Todd's 2010 &lt;a href="https://doi.org/10.1086/651235" rel="noopener noreferrer"&gt;meta-analysis of choice-overload experiments&lt;/a&gt; examined 63 conditions from 50 published and unpublished experiments with 5,036 participants. The average effect was close to zero, while the variation between studies was substantial. In some contexts, larger assortments harmed decisions. In others, they helped or made little difference.&lt;/p&gt;

&lt;p&gt;That is not evidence that choice overload is imaginary. It is evidence that assortment size alone is an incomplete explanation.&lt;/p&gt;

&lt;p&gt;Chernev, Böckenholt, and Goodman's later &lt;a href="https://doi.org/10.1016/j.jcps.2014.08.002" rel="noopener noreferrer"&gt;conceptual review and meta-analysis&lt;/a&gt; analyzed 99 observations involving 7,202 participants and identified four conditions that reliably shape overload risk:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choice-set complexity:&lt;/strong&gt; Options contain many attributes, attributes are difficult to compare, or alternatives are very similar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision-task difficulty:&lt;/strong&gt; The user faces time pressure, incomplete information, uncertain consequences, or a demanding evaluation process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preference uncertainty:&lt;/strong&gt; The user does not yet know which attributes matter or how to trade one benefit against another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision goal:&lt;/strong&gt; The user wants to minimize effort rather than invest deeply in finding an optimal result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives designers a stronger model. The question is not "How many options are too many?" It is "How much unresolved decision work have we placed in front of this person?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Choice Overload and Hick's Law Are Related, Not Interchangeable
&lt;/h2&gt;

&lt;p&gt;Choice overload is often paired with Hick's Law, but they describe different outcomes.&lt;/p&gt;

&lt;p&gt;W. E. Hick's 1952 experiments on &lt;a href="https://doi.org/10.1080/17470215208416600" rel="noopener noreferrer"&gt;the rate of information gain&lt;/a&gt; studied choice reaction time. As the uncertainty among possible stimulus-response pairs increased, reaction time increased in a predictable relationship. In interface language, selecting one item from a larger set of equally plausible actions generally takes longer than selecting from a smaller set.&lt;/p&gt;

&lt;p&gt;Choice overload reaches beyond reaction time. It can involve postponing the decision, abandoning it, feeling less satisfied afterward, or continuing to wonder whether an unchosen option was better.&lt;/p&gt;

&lt;p&gt;This difference changes how I apply the concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hick's Law helps evaluate &lt;strong&gt;selection speed&lt;/strong&gt; among visible actions.&lt;/li&gt;
&lt;li&gt;Choice overload helps evaluate &lt;strong&gt;motivation, confidence, completion, and satisfaction&lt;/strong&gt; across a decision.&lt;/li&gt;
&lt;li&gt;Hick's Law is most direct when options are known and the task is to select.&lt;/li&gt;
&lt;li&gt;Choice overload becomes especially relevant when users must first understand what the options mean and decide what they value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A navigation menu with twelve familiar destinations may slow scanning without creating meaningful overload. Three health-insurance plans can create overload because the consequences are important and the tradeoffs are difficult. Counting options without examining the decision hides that difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Decision Tax
&lt;/h2&gt;

&lt;p&gt;The decision tax is the total work an interface transfers to the user before they can choose with confidence. I break it into five costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Discovery Cost
&lt;/h3&gt;

&lt;p&gt;What must the user inspect before they can form a reasonable shortlist?&lt;/p&gt;

&lt;p&gt;Discovery cost rises when every option receives equal visual weight, labels are vague, categories reflect the company's organization instead of the user's goal, or important differences are buried in detail pages.&lt;/p&gt;

&lt;p&gt;Search and filters can lower discovery cost, but only when their vocabulary matches what people know. A filter labeled "deployment topology" may be technically precise and useless to a buyer who thinks in terms of "works with my existing server."&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparison Cost
&lt;/h3&gt;

&lt;p&gt;How much work is required to compare the remaining options on the same dimensions?&lt;/p&gt;

&lt;p&gt;Comparison becomes expensive when cards describe different attributes, units change, features appear in inconsistent orders, or the user must remember facts while moving between pages. A side-by-side table is useful because it externalizes memory and aligns differences. It does not help when the table contains 80 undifferentiated rows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interpretation Cost
&lt;/h3&gt;

&lt;p&gt;Does the user understand why a difference matters?&lt;/p&gt;

&lt;p&gt;Technical products often expose implementation details before translating their consequences. Storage, requests, seats, integrations, response time, and support levels matter only after the user can connect them to a real need. Good content gives the attribute a job instead of presenting it as a number.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consequence Cost
&lt;/h3&gt;

&lt;p&gt;How difficult or risky is it to be wrong?&lt;/p&gt;

&lt;p&gt;Choosing a playlist theme has a low consequence cost. Selecting a billing plan, deleting data, changing permissions, or configuring a deployment has a higher one. High-consequence choices need clearer previews, stronger comparison, confirmation, reversibility, and honest explanations of what changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regret Cost
&lt;/h3&gt;

&lt;p&gt;How much does the interface keep unchosen alternatives psychologically active after the decision?&lt;/p&gt;

&lt;p&gt;When every option claims a unique advantage, users can imagine a benefit they sacrificed no matter what they select. Clear tradeoffs, a transparent default, easy plan changes, and a reversible trial reduce the pressure to make a permanently perfect choice.&lt;/p&gt;

&lt;p&gt;The decision tax explains why simply deleting options is an incomplete fix. A team can reduce six plans to three and still leave every cost in place. Better design removes unnecessary work while preserving options that represent real differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Catalog Is Not a Decision Surface
&lt;/h2&gt;

&lt;p&gt;One of the most useful distinctions in interface design is the difference between how many options a system supports and how many it asks the user to evaluate at once.&lt;/p&gt;

&lt;p&gt;An online store may need a large catalog. A developer tool may support dozens of integrations. A dashboard may expose hundreds of reports. The product does not need to flatten that inventory into one visual decision.&lt;/p&gt;

&lt;p&gt;The interface can stage the work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;search when the user knows the target&lt;/li&gt;
&lt;li&gt;categories when the user recognizes a goal&lt;/li&gt;
&lt;li&gt;filters when attributes are understood&lt;/li&gt;
&lt;li&gt;guided questions when preferences are still forming&lt;/li&gt;
&lt;li&gt;recommendations when the reason can be explained&lt;/li&gt;
&lt;li&gt;comparison when a shortlist exists&lt;/li&gt;
&lt;li&gt;progressive disclosure when detail becomes relevant later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not hiding choice. It is sequencing choice while keeping the broader catalog reachable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison Is an Interface, Not a Spreadsheet Dump
&lt;/h2&gt;

&lt;p&gt;When options are genuinely different, comparison is necessary. The design responsibility is to make those differences legible.&lt;/p&gt;

&lt;p&gt;Pricing pages expose this problem clearly. Teams often add plans over time, write each card independently, attach multiple badges, and list whichever features make that tier sound strongest. The cards become advertisements rather than a comparison surface.&lt;/p&gt;

&lt;p&gt;A useful comparison aligns the options around shared questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who is this for?&lt;/li&gt;
&lt;li&gt;What limit changes?&lt;/li&gt;
&lt;li&gt;Which capability becomes available?&lt;/li&gt;
&lt;li&gt;What remains the same?&lt;/li&gt;
&lt;li&gt;What happens if the user outgrows the choice?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh2q3t0zgtdv5axdre2ut.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh2q3t0zgtdv5axdre2ut.webp" alt="A before-and-after pricing example contrasting six inconsistent option cards with three aligned plans and a shared feature comparison." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The better surface does not pretend the other choices do not exist. It gives users common criteria, an explainable recommendation, and a path to full detail.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The recommendation deserves special care. A "Most Popular" badge may reduce effort, but it can also become a dark pattern when it exists only to steer buyers toward the most profitable tier. An honest default states the reason: "Best for teams that need approvals" is more useful than "Best Value." The recommendation should help the user map a plan to a situation, not borrow authority the interface has not earned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preserve Agency While Reducing Work
&lt;/h2&gt;

&lt;p&gt;Choice architecture becomes manipulative when simplification quietly removes meaningful alternatives or preselects the outcome that benefits the business. The goal is not to make users choose faster at any cost. The goal is to make the decision understandable.&lt;/p&gt;

&lt;p&gt;I use five principles:&lt;/p&gt;

&lt;h3&gt;
  
  
  Prefer Meaningful Differences
&lt;/h3&gt;

&lt;p&gt;Options should represent real tradeoffs. If two plans differ only because the product team wants another price anchor, the interface inherits comparison work without adding meaningful agency.&lt;/p&gt;

&lt;p&gt;Before designing cards, ask whether each option deserves to exist. Information architecture cannot permanently repair a weak product architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give the User a Starting Point
&lt;/h3&gt;

&lt;p&gt;A featured option, saved configuration, sensible default, or short guided question can reduce the blank-page problem. The starting point should be transparent and reversible.&lt;/p&gt;

&lt;p&gt;Defaults are especially powerful, which means they require restraint. Use them to express a safe, common choice, not to sneak consent, upgrades, or recurring charges past the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make Tradeoffs Comparable
&lt;/h3&gt;

&lt;p&gt;Use consistent labels, units, order, and levels of detail. Keep the attributes people use to decide visible together. Move secondary specifications behind expansion only after the primary differences are clear.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let People Narrow Before They Compare
&lt;/h3&gt;

&lt;p&gt;Filtering is not merely a catalog feature. It is a decision-making tool. Good filters remove irrelevant options based on criteria the user understands and preserve the state so the user can revise the shortlist without starting over.&lt;/p&gt;

&lt;p&gt;This is one reason I prefer semantic, URL-backed filters for substantial content and product collections. They make the current decision state visible, navigable, and shareable. When implemented server-side, they can also preserve crawlable source content while keeping filtered utility URLs out of the index through deliberate canonical and robots behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep the Full Set Reachable
&lt;/h3&gt;

&lt;p&gt;Progressive disclosure should reduce immediate demand without creating a dead end. "Show all," "Compare features," and removable filter chips give people control over how much complexity they want to take on.&lt;/p&gt;

&lt;p&gt;The interface should support both the person who wants guidance and the expert who already knows what they need.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SCOPE Review
&lt;/h2&gt;

&lt;p&gt;Before I ship a decision-heavy interface, I review it through five questions: Set, Compare, Organize, Progressively reveal, and Enable narrowing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhp1o5dcrv3450wfnvn8.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhp1o5dcrv3450wfnvn8.webp" alt="The SCOPE review: set the decision, compare consistently, organize meaningfully, progressively reveal detail, and enable users to narrow the set." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SCOPE is not a rule for making every interface smaller. It is a review for making the user's decision clearer.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  S: Set the Decision
&lt;/h3&gt;

&lt;p&gt;What is the user actually choosing?&lt;/p&gt;

&lt;p&gt;This sounds obvious, but interfaces often mix several decisions in one surface. A checkout may ask the user to select shipping speed, insurance, gift options, payment method, account creation, and marketing consent without separating their purposes.&lt;/p&gt;

&lt;p&gt;Write the decision as one sentence: "Choose the plan that supports your team size and approval needs." If the sentence needs several unrelated clauses, the interface may need stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  C: Compare Consistently
&lt;/h3&gt;

&lt;p&gt;Can alternatives be evaluated on shared dimensions?&lt;/p&gt;

&lt;p&gt;Normalize the data before designing the cards. If one product lists capacity, another lists speed, and a third lists compatibility, visual polish will not make them comparable. Define the decision attributes, units, missing-value behavior, and display order as part of the product model.&lt;/p&gt;

&lt;p&gt;Consistency also matters for accessibility. Repeated structures should preserve heading order, label controls clearly, and avoid making color or position the only signal for a difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  O: Organize Meaningfully
&lt;/h3&gt;

&lt;p&gt;Can users recognize useful groups before inspecting every item?&lt;/p&gt;

&lt;p&gt;Group by user goal, task, compatibility, or another distinction that helps eliminate irrelevant options. Avoid categories that exist only because they mirror internal departments or database fields.&lt;/p&gt;

&lt;p&gt;Organization should reduce scanning without implying false exclusivity. A tool can belong to more than one useful category when the underlying model supports it.&lt;/p&gt;

&lt;h3&gt;
  
  
  P: Progressively Reveal
&lt;/h3&gt;

&lt;p&gt;What information is required for this stage of the decision?&lt;/p&gt;

&lt;p&gt;Show enough to understand the tradeoff, then provide detail on demand. Progressive disclosure fails when essential costs, restrictions, or consequences are hidden behind interaction. It also fails when the collapsed label is too vague to predict what it contains.&lt;/p&gt;

&lt;p&gt;The right test is not whether content fits above the fold. It is whether the user can make the next decision without carrying unnecessary information in working memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  E: Enable Narrowing
&lt;/h3&gt;

&lt;p&gt;Can users reduce the set using criteria they understand?&lt;/p&gt;

&lt;p&gt;Search, filters, sort controls, guided questions, and comparison trays serve different forms of intent. Search supports a known target. Filters support known attributes. Guided questions help form preferences. Comparison supports a shortlist.&lt;/p&gt;

&lt;p&gt;Do not force one control to perform every job. A search field cannot replace a useful category system, and dozens of filters cannot help someone who does not know what the attributes mean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Choice Architecture in the Front End
&lt;/h2&gt;

&lt;p&gt;Choice overload is not solved only in a design file. The implementation determines whether the support survives real content, responsive layouts, assistive technology, and changing product data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model Options Around Comparable Attributes
&lt;/h3&gt;

&lt;p&gt;Use structured data for the facts that drive comparison. A pricing tier should not store its entire meaning in an arbitrary marketing paragraph. Team size, limits, included capabilities, support level, and upgrade behavior should be fields that can be rendered consistently.&lt;/p&gt;

&lt;p&gt;Structured attributes also make it possible to test missing values, prevent contradictory claims, generate accessible tables, and reuse the same source across cards, comparison views, and metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep Filter State Understandable
&lt;/h3&gt;

&lt;p&gt;The selected state should survive navigation, refresh, and sharing when the task benefits from it. URL parameters are often appropriate for filters, but they need deliberate SEO handling. The canonical collection remains the indexable source while utility combinations can be &lt;code&gt;noindex, follow&lt;/code&gt; when they do not represent distinct search destinations.&lt;/p&gt;

&lt;p&gt;This avoids solving a UX problem by creating an indexing problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Native Controls
&lt;/h3&gt;

&lt;p&gt;Native selects, checkboxes, radio groups, buttons, and links provide semantics and keyboard behavior that custom clickable containers must rebuild. A plan card can be visually rich while its selection control remains a real radio input with a visible label.&lt;/p&gt;

&lt;p&gt;For progressive disclosure, the trigger needs an accessible name, an expanded state, and predictable focus behavior. For comparison tables, row and column headers need semantic relationships. For recommendations, the reason must be available as text, not only a colored badge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design the Small Screen as a Decision Sequence
&lt;/h3&gt;

&lt;p&gt;A desktop comparison table cannot simply shrink until it becomes unreadable. On mobile, preserve the shared criteria and let users compare a small number of options at a time. Sticky option headers, a two-item comparison tray, or criterion-by-criterion sections can maintain context without forcing horizontal memory.&lt;/p&gt;

&lt;p&gt;Responsive design should change the presentation, not erase the information needed to choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Measure Choice Overload
&lt;/h2&gt;

&lt;p&gt;Overload is easy to label after a design review and harder to prove. I look for a pattern across behavior rather than one metric.&lt;/p&gt;

&lt;p&gt;Useful signals include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Time to first meaningful action:&lt;/strong&gt; How long does it take to begin narrowing or comparing?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision completion:&lt;/strong&gt; Do people finish, postpone, or abandon the choice?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backtracking:&lt;/strong&gt; How often do users reopen options or repeat the same comparison?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selection volatility:&lt;/strong&gt; How frequently does the choice change before commitment?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Support-tool use:&lt;/strong&gt; Are filters, comparisons, recommendations, or guided questions helping?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errors and reversals:&lt;/strong&gt; Do people immediately undo, downgrade, cancel, or contact support?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence:&lt;/strong&gt; Can users explain why their selected option fits their needs?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In moderated research, I ask participants to state their decision criteria before they begin. If they cannot, I watch whether the interface helps them form those criteria or simply makes them inspect more cards.&lt;/p&gt;

&lt;p&gt;The experiment should compare decision support, not only assortment size. Test a raw set against grouped options, aligned comparison, guided narrowing, or a transparent default. That tells the team which form of support reduces the tax without removing needed choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  When More Choice Is the Better Design
&lt;/h2&gt;

&lt;p&gt;Large assortments can be a feature when the interface and context support them.&lt;/p&gt;

&lt;p&gt;More choice is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;users arrive with clear preferences or a known target&lt;/li&gt;
&lt;li&gt;meaningful variation exists across the audience&lt;/li&gt;
&lt;li&gt;search and filters quickly remove irrelevant options&lt;/li&gt;
&lt;li&gt;experts need precision or control&lt;/li&gt;
&lt;li&gt;the task is repeated and users can build fluency&lt;/li&gt;
&lt;li&gt;alternatives are easy to compare on stable attributes&lt;/li&gt;
&lt;li&gt;choosing incorrectly is inexpensive or reversible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The right move is often layered access: a strong default for common needs, guided controls for developing preferences, and complete control for experts.&lt;/p&gt;

&lt;p&gt;That is the same principle I use in &lt;a href="https://www.ryanverwey.dev/blog/the-novelty-budget-familiar-vs-novel-ui" rel="noopener noreferrer"&gt;The Novelty Budget&lt;/a&gt;. Familiar structure creates a stable core. Product-specific capability can live at the edge. Here, the stable core is a comprehensible decision, and the edge is the breadth of choice the product genuinely needs to support.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Team Review
&lt;/h2&gt;

&lt;p&gt;Before release, I ask the team to answer these questions together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Product:&lt;/strong&gt; Which options represent meaningful differences, and which exist for internal reasons?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design:&lt;/strong&gt; Can a user identify the decision and the primary tradeoffs without opening every option?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content and engineering:&lt;/strong&gt; Are labels clear and attributes structured consistently enough for comparison?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; Can people compare without relying on pointer precision, color, or visual memory?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Research and analytics:&lt;/strong&gt; Are we measuring confident completion, reversals, and abandonment instead of attention alone?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This keeps choice overload from becoming a cosmetic diagnosis. A confusing surface may expose inconsistent tiers, missing content strategy, or weak data modeling. The interface is often where organizational ambiguity becomes visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;More choice is not automatically empowering, and less choice is not automatically usable.&lt;/p&gt;

&lt;p&gt;Choice overload appears when the interface presents more unresolved comparison, interpretation, consequence, and regret than the user can justify for the task. The threshold moves with the person, the options, the stakes, and the support built around the decision.&lt;/p&gt;

&lt;p&gt;Do not chase a magic number. Define the decision. Align the differences. Organize around user goals. Reveal detail when it becomes useful. Give people tools to narrow the set, and keep the broader choice reachable when it represents real value.&lt;/p&gt;

&lt;p&gt;The goal is not to choose for the user. It is to stop charging them unnecessary work for the right to choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Chernev, A., Böckenholt, U., &amp;amp; Goodman, J. (2015). &lt;a href="https://doi.org/10.1016/j.jcps.2014.08.002" rel="noopener noreferrer"&gt;Choice overload: A conceptual review and meta-analysis&lt;/a&gt;. &lt;em&gt;Journal of Consumer Psychology, 25&lt;/em&gt;(2), 333-358.&lt;/p&gt;

&lt;p&gt;Hick, W. E. (1952). &lt;a href="https://doi.org/10.1080/17470215208416600" rel="noopener noreferrer"&gt;On the rate of gain of information&lt;/a&gt;. &lt;em&gt;Quarterly Journal of Experimental Psychology, 4&lt;/em&gt;(1), 11-26.&lt;/p&gt;

&lt;p&gt;Iyengar, S. S., &amp;amp; Lepper, M. R. (2000). &lt;a href="https://doi.org/10.1037/0022-3514.79.6.995" rel="noopener noreferrer"&gt;When choice is demotivating: Can one desire too much of a good thing?&lt;/a&gt;. &lt;em&gt;Journal of Personality and Social Psychology, 79&lt;/em&gt;(6), 995-1006.&lt;/p&gt;

&lt;p&gt;Scheibehenne, B., Greifeneder, R., &amp;amp; Todd, P. M. (2010). &lt;a href="https://doi.org/10.1086/651235" rel="noopener noreferrer"&gt;Can there ever be too many options? A meta-analytic review of choice overload&lt;/a&gt;. &lt;em&gt;Journal of Consumer Research, 37&lt;/em&gt;(3), 409-425.&lt;/p&gt;

&lt;p&gt;Toffler, A. (1970). &lt;a href="https://search.worldcat.org/title/Future-shock/oclc/570341844" rel="noopener noreferrer"&gt;&lt;em&gt;Future shock&lt;/em&gt;&lt;/a&gt;. Random House.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;What is choice overload in UI/UX design?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Choice overload is the decline in motivation, confidence, completion, or satisfaction that can occur when a decision requires more comparison work than a user can comfortably manage. It depends on the complexity of the options, the task, the user's preferences, and the consequences, not only the number of choices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is choice overload the same as the paradox of choice?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The terms are often used interchangeably. Both describe situations where additional options can make choosing harder or less satisfying. In interface work, "choice overload" is useful because it focuses attention on observable decision behavior and the conditions producing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How is choice overload different from Hick's Law?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hick's Law describes how decision time changes as uncertainty among possible responses increases. Choice overload concerns broader outcomes such as deferral, abandonment, confidence, regret, and satisfaction. A selection can take longer without becoming overload, and a small high-stakes set can create overload even when it contains few options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How many options should an interface show?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is no universal limit. Show enough options to represent meaningful differences, then reduce decision work through grouping, consistent comparison, progressive disclosure, defaults, search, and filtering. Test whether users can explain and complete the decision confidently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do filters solve choice overload?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Filters help when users understand the attributes and can identify what matters. They are less useful when preferences are still forming or labels use unfamiliar language. In those cases, guided questions, recommendations with reasons, and clear categories may provide a better starting point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the SCOPE review?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SCOPE is my five-part review for decision-heavy interfaces: Set the decision, Compare consistently, Organize meaningfully, Progressively reveal detail, and Enable narrowing. It is designed to reduce unnecessary decision work without removing meaningful user choice.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>choicearchitecture</category>
      <category>interactiondesign</category>
      <category>userresearch</category>
    </item>
    <item>
      <title>The Novelty Budget: Why Good Interfaces Borrow Before They Invent</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 01 Sep 2026 14:34:24 +0000</pubDate>
      <link>https://dev.to/rverwey/the-novelty-budget-why-good-interfaces-borrow-before-they-invent-blf</link>
      <guid>https://dev.to/rverwey/the-novelty-budget-why-good-interfaces-borrow-before-they-invent-blf</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.ryanverwey.dev/blog/the-novelty-budget-familiar-vs-novel-ui" rel="noopener noreferrer"&gt;ryanverwey.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Familiar interfaces are not successful because designers lack imagination. They are successful because users arrive with experience already installed. A cart icon, an underlined link, a Back action, a visible form label, and a predictable checkout sequence let people act before they have studied the product.&lt;/p&gt;

&lt;p&gt;Novel interfaces are not automatically brave, innovative, or better. Every unfamiliar behavior asks the user to stop, inspect, predict, test, and remember. That learning can be worthwhile, but only when the product returns more value than the interaction costs to understand.&lt;/p&gt;

&lt;p&gt;My working rule is simple: &lt;strong&gt;every interface has a novelty budget&lt;/strong&gt;. Spend it on the part of the experience that makes the product meaningfully different. Borrow the rest from patterns people already know.&lt;/p&gt;

&lt;p&gt;This first entry in my &lt;strong&gt;Interface Tensions&lt;/strong&gt; series explains how I decide what to preserve, what to challenge, and what evidence I want before an unfamiliar pattern ships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Familiarity Is Stored Work
&lt;/h2&gt;

&lt;p&gt;When a user recognizes a pattern, they are not beginning from zero. They are applying prior practice from other products, physical objects, and repeated tasks. The designer benefits from work that someone else already paid for.&lt;/p&gt;

&lt;p&gt;That is the useful core of Jakob's Law: people spend most of their time using products other than ours, so their expectations are shaped elsewhere. Megan Chan's discussion of &lt;a href="https://www.nngroup.com/articles/mental-models/" rel="noopener noreferrer"&gt;mental models&lt;/a&gt; describes those expectations as beliefs people use to predict what a system will do. The belief does not have to be technically accurate to guide behavior. If an interface looks like a search field, people expect it to search. If a logo sits in a site header, many people expect it to return them home. If Back looks available, they expect it to reverse the last navigational step.&lt;/p&gt;

&lt;p&gt;This is why familiarity is more than a visual preference. It is stored work. It carries four practical advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Faster orientation.&lt;/strong&gt; People can identify where they are and what they can do without reading instructions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lower memory demand.&lt;/strong&gt; Visible, recognizable options reduce the need to recall commands or hidden rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More confident prediction.&lt;/strong&gt; People can estimate what will happen before they act.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster recovery.&lt;/strong&gt; Familiar error messages, undo actions, and Back behavior help people recover when something goes wrong.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Raluca Budiu's explanation of &lt;a href="https://www.nngroup.com/articles/recognition-and-recall/" rel="noopener noreferrer"&gt;recognition versus recall&lt;/a&gt; matters here. Recognition gives memory more cues. A visible list of options is easier to work with than a blank field that expects the user to remember a command. A labeled icon is usually easier to interpret than an icon whose meaning must be learned. A recent-history list is easier than reconstructing where you were from memory.&lt;/p&gt;

&lt;p&gt;The strongest interfaces often feel obvious not because they are simple underneath, but because they preserve enough familiar cues that the underlying complexity does not become the user's first problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpko861622q589qmas5bq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpko861622q589qmas5bq.webp" alt="The novelty budget shows familiar conventions at a low orientation cost and strategic novelty at a higher cost that must create durable value." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The novelty budget treats unfamiliarity as a real product cost. The cost is justified only when the benefit survives beyond the first moment of surprise.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Novelty Is a Cost Before It Becomes a Capability
&lt;/h2&gt;

&lt;p&gt;Design teams experience a product differently from the people using it. We see the same screens for weeks or months. We know the vocabulary, the edge cases, the roadmap, and the logic behind every exception. Familiarity can make a working interface feel stale to the team long before it feels stale to the user.&lt;/p&gt;

&lt;p&gt;That imbalance is dangerous. A redesign can solve the team's boredom while creating the user's confusion.&lt;/p&gt;

&lt;p&gt;Nielsen Norman Group's article on the &lt;a href="https://www.nngroup.com/articles/power-law-learning/" rel="noopener noreferrer"&gt;power law of learning&lt;/a&gt; makes the underlying tradeoff clear: a common pattern benefits from practice accumulated across many products, while a new pattern begins at the steep end of its learning curve. The new design may eventually become more efficient, but the user has to remain engaged long enough to reach that point.&lt;/p&gt;

&lt;p&gt;This does not mean novelty is bad. It means novelty has an invoice.&lt;/p&gt;

&lt;p&gt;An unfamiliar pattern may require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;additional explanation or contextual guidance&lt;/li&gt;
&lt;li&gt;clearer system feedback after each action&lt;/li&gt;
&lt;li&gt;a fallback for users who do not discover the new behavior&lt;/li&gt;
&lt;li&gt;stronger error recovery because prediction is weaker&lt;/li&gt;
&lt;li&gt;accessibility testing across keyboard, touch, zoom, and assistive technology&lt;/li&gt;
&lt;li&gt;repeated exposure before the interaction becomes efficient&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those costs are reasonable when the new behavior unlocks something meaningful. They are wasteful when the change exists mainly to make a common task look distinctive.&lt;/p&gt;

&lt;p&gt;Replacing a conventional checkout flow with a radial gesture menu is novelty attached to a high-risk commodity task. Giving a data analyst a new way to manipulate a complex relationship directly on a canvas may be novelty attached to the actual value of the product. Both interactions can look original. Only one has a credible reason to ask the user to learn.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Difference Between Visual Novelty and Behavioral Novelty
&lt;/h2&gt;

&lt;p&gt;One reason teams argue past each other is that "novel" can describe several different things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual novelty&lt;/strong&gt; changes how the experience feels. It can come from typography, illustration, color relationships, composition, rhythm, photography, or motion. A page can look unmistakably original while its links, forms, menus, and controls remain conventional.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structural novelty&lt;/strong&gt; changes where information lives or how the experience is organized. A product may replace a familiar top navigation with a persistent workspace rail, reorganize content around objects instead of pages, or introduce a new hierarchy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioral novelty&lt;/strong&gt; changes what actions mean and how the user performs them. This is the most expensive form because it changes prediction. The same gesture may produce a different result, a familiar control may behave in an unfamiliar way, or a task may require a sequence the user has never practiced.&lt;/p&gt;

&lt;p&gt;These forms should not be treated as equally risky. Visual expression can create a memorable brand without forcing the user to relearn basic operation. Structural change requires stronger orientation. Behavioral change needs the strongest justification, feedback, and testing.&lt;/p&gt;

&lt;p&gt;That separation gives a team more room than the familiar-versus-novel debate usually suggests. We do not have to choose between a generic interface and an experimental one. We can keep the interaction contract familiar while making the experience visually specific to the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Layers of Interface Change
&lt;/h2&gt;

&lt;p&gt;I use three layers to decide where invention belongs: safety, product, and expression.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjo7fr7hs0op9ujvdbrf.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpjo7fr7hs0op9ujvdbrf.webp" alt="Three layers of interface change: preserve conventions in the safety layer, challenge them selectively in the product layer, and differentiate freely in the expression layer." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The safest approach is not uniform conservatism. It is assigning a different level of freedom to each layer of the experience.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Safety Layer: Preserve the Contract
&lt;/h3&gt;

&lt;p&gt;The safety layer includes the actions people rely on to move, understand consequences, submit information, and recover. It covers navigation, form labels, focus behavior, destructive actions, confirmation, undo, status, and error messages.&lt;/p&gt;

&lt;p&gt;This layer should usually be boring in the best possible way. A destructive button should look and behave like a destructive action. A keyboard user should encounter controls in a meaningful order. A required field should be identified before submission. A Back action should not secretly jump to an unrelated hierarchy level.&lt;/p&gt;

&lt;p&gt;Consistency here is also an accessibility concern. The W3C guidance for &lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/consistent-navigation.html" rel="noopener noreferrer"&gt;WCAG 2.2 Success Criterion 3.2.3&lt;/a&gt; explains that repeated navigation in a consistent relative order helps people predict where functions will appear. That predictability is particularly important for users working through screen magnification, sequential screen-reader output, cognitive limitations, or limited motor input.&lt;/p&gt;

&lt;p&gt;Novelty in the safety layer can make the product memorable for the wrong reason. If a person has to learn your unique meaning for Save, Close, Back, Delete, Search, or Submit, the interface is spending attention on infrastructure instead of value.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Product Layer: Challenge Selectively
&lt;/h3&gt;

&lt;p&gt;The product layer is where the application performs its defining work. This is the most defensible place for behavioral novelty because a better interaction can become a real capability.&lt;/p&gt;

&lt;p&gt;An AI-assisted editor may need a new pattern for reviewing proposed changes before they are applied. A spatial planning tool may need direct manipulation that has no close equivalent in a document interface. A collaboration product may need a new way to show presence, ownership, or branching work. A complex audit product may need to turn hundreds of findings into a prioritized repair plan instead of another flat report.&lt;/p&gt;

&lt;p&gt;This is where I am willing to challenge convention, but I still want familiar anchors around the new behavior. The user should recognize the objects, labels, state changes, and recovery options even if the core workflow is new.&lt;/p&gt;

&lt;p&gt;While building &lt;a href="https://www.ryanverwey.dev/blog/building-optimize-echo-effect-audit-tool" rel="noopener noreferrer"&gt;Optimize&lt;/a&gt;, for example, the distinctive value was not inventing a strange new way to click through a report. The value was in turning SEO, AEO, GEO, crawler, structured-data, and accessibility findings into a clearer decision surface. Familiar report organization provided the foothold. The product logic supplied the difference.&lt;/p&gt;

&lt;p&gt;The same principle shapes design-system work. In &lt;a href="https://www.ryanverwey.dev/blog/atomic-design-system-angular" rel="noopener noreferrer"&gt;building an Angular design system&lt;/a&gt;, I found that consistency at the component and token level creates room for teams to solve higher-order product problems. If every button, form field, spacing decision, or responsive pattern is reinvented locally, the organization spends its novelty budget before it reaches anything customers value.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Expression Layer: Differentiate Deliberately
&lt;/h3&gt;

&lt;p&gt;The expression layer includes typography, imagery, pacing, transitions, tone, editorial composition, and moments of delight. This layer can carry far more novelty because it can create distinction without changing the meaning of basic actions.&lt;/p&gt;

&lt;p&gt;A portfolio, cultural story, game, campaign, or product launch may benefit from visual surprise and exploration. An operational dashboard used throughout a workday usually needs more restraint. The right amount of expression depends on context, but expression is generally a safer place to be bold than navigation or error recovery.&lt;/p&gt;

&lt;p&gt;The important distinction is that visual originality should support comprehension, not compete with it. Motion can show a relationship, reveal state, or guide attention. It can also delay access and make the user wait for the designer's performance to finish. Typography can establish a strong voice. It can also reduce readability. An unusual layout can create a memorable sequence. It can also hide the next action.&lt;/p&gt;

&lt;p&gt;Novelty becomes useful when it clarifies the product's identity or content while leaving the interaction contract intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Familiarity Is Not the Same as Sameness
&lt;/h2&gt;

&lt;p&gt;Following conventions does not require cloning competitors. A familiar pattern describes an expectation, not a finished appearance.&lt;/p&gt;

&lt;p&gt;Consider a card. The convention is not a particular shadow, border radius, or color. The convention is that related information is grouped into a recognizable unit, often with a clear hierarchy and an action that belongs to that unit. A team can express that relationship through editorial spacing, a dense utility row, a bordered region, an image-led layout, or no visible container at all.&lt;/p&gt;

&lt;p&gt;The same is true for navigation. Familiarity means users can identify where navigation is, understand the available destinations, perceive the current location, and operate it with the inputs they use. It does not require every site to share the same typography or visual composition.&lt;/p&gt;

&lt;p&gt;This is where design systems are often misunderstood. A design system should not flatten every product into one visual template. It should stabilize the decisions that benefit from repetition so designers and developers can spend their attention on context. Tokens, accessible controls, interaction states, and semantic patterns create a dependable grammar. Products still decide what to say with it.&lt;/p&gt;

&lt;p&gt;The goal is not sameness. The goal is transferable confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Novelty Earns Its Place
&lt;/h2&gt;

&lt;p&gt;Novelty has the strongest case in four situations.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Existing Pattern Cannot Express the Capability
&lt;/h3&gt;

&lt;p&gt;Sometimes a product does something that familiar controls do not represent well. Forcing a new capability into an old metaphor can create more confusion than teaching a new pattern.&lt;/p&gt;

&lt;p&gt;The test is whether the innovation changes the user's power, not merely the presentation. If a new interaction lets people see relationships, compare alternatives, automate a repeated task, or collaborate in a way the old pattern could not support, the learning cost may have a durable return.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repetition Will Repay the Learning
&lt;/h3&gt;

&lt;p&gt;An interaction used once must be immediately understandable. An interaction used dozens of times a day can justify a short learning curve if it becomes significantly faster or clearer with practice.&lt;/p&gt;

&lt;p&gt;This is why expert tools can support shortcuts, direct manipulation, command palettes, and dense controls that would be inappropriate in a one-time consumer flow. The user has repeated opportunities to convert learning into fluency.&lt;/p&gt;

&lt;p&gt;Frequency does not excuse a bad first experience. It changes the return calculation. The product still needs clear onboarding, visible feedback, and a path back to safety.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exploration Is the Task
&lt;/h3&gt;

&lt;p&gt;Some experiences are built to encourage discovery rather than rapid completion. Interactive storytelling, data exploration, creative tools, and games may use surprise as part of the value.&lt;/p&gt;

&lt;p&gt;In those cases, a completely predictable sequence can work against the purpose. The interface should still communicate what is interactive, maintain keyboard and touch access, and protect the user from dead ends. Exploration is not a license to remove orientation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Pattern Creates Real Differentiation
&lt;/h3&gt;

&lt;p&gt;A product may need a recognizable interaction of its own, especially when the workflow is central to its identity. The strongest signature interactions become shorthand for the product because they are useful first and distinctive second.&lt;/p&gt;

&lt;p&gt;That order matters. If the only defense is "nobody else does it this way," the design has demonstrated difference, not value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Familiarity Should Usually Win
&lt;/h2&gt;

&lt;p&gt;Familiarity should dominate when the cost of error is high, the task is infrequent, the user is under pressure, or the interaction is only supporting infrastructure.&lt;/p&gt;

&lt;p&gt;That includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication and account recovery&lt;/li&gt;
&lt;li&gt;payments, checkout, and subscription changes&lt;/li&gt;
&lt;li&gt;consent and privacy decisions&lt;/li&gt;
&lt;li&gt;destructive operations&lt;/li&gt;
&lt;li&gt;navigation and wayfinding&lt;/li&gt;
&lt;li&gt;form completion and validation&lt;/li&gt;
&lt;li&gt;accessibility controls&lt;/li&gt;
&lt;li&gt;system status and error recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are poor places to demand interpretation. A user who is trying to recover an account or understand a failed payment is not looking for a signature interaction. They need clarity, predictability, and a safe next step.&lt;/p&gt;

&lt;p&gt;Familiarity should also win when novelty is being used to hide weak information architecture. A dramatic menu cannot repair unclear labels. Motion cannot compensate for missing hierarchy. A tutorial cannot permanently solve a control that does not explain itself.&lt;/p&gt;

&lt;p&gt;If the design needs a paragraph of instruction before the first click, the problem may not be insufficient onboarding. The problem may be the interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The FUSE Test
&lt;/h2&gt;

&lt;p&gt;Before shipping an unfamiliar pattern, I use four questions. Together they form the FUSE test: Familiar anchor, User benefit, Safe failure, and Evidence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F92187e5vqa4q1hfhmoz0.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F92187e5vqa4q1hfhmoz0.webp" alt="The FUSE test asks whether an unfamiliar interface has a familiar anchor, a durable user benefit, safe failure and recovery, and evidence from observed behavior." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A novel interaction should not ship on enthusiasm alone. Each part of FUSE reduces a different kind of risk.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Familiar Anchor
&lt;/h3&gt;

&lt;p&gt;What does the user already know that gives them a foothold?&lt;/p&gt;

&lt;p&gt;The anchor may be a recognizable object, label, spatial relationship, or sequence. A new canvas interaction might still use familiar selection handles, undo, zoom controls, and keyboard shortcuts. An AI workflow might still present a visible plan, explicit approval, progress status, and a reviewable result.&lt;/p&gt;

&lt;p&gt;If nothing is familiar, the product is asking the user to learn the domain and the interface at the same time.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Benefit
&lt;/h3&gt;

&lt;p&gt;What durable value justifies the learning cost?&lt;/p&gt;

&lt;p&gt;"It feels fresh" is not enough. The change should improve speed, comprehension, control, capability, or expression in a way that matters to the intended user. The benefit should still exist after the novelty wears off.&lt;/p&gt;

&lt;p&gt;This is the question that protects a team from confusing attention with usefulness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safe Failure
&lt;/h3&gt;

&lt;p&gt;What happens when the user's prediction is wrong?&lt;/p&gt;

&lt;p&gt;Can they undo the action? Is lost work restored? Does the interface explain the result? Is there a conventional alternative? Does keyboard navigation reach the same outcome? Can a user leave the experiment without being trapped?&lt;/p&gt;

&lt;p&gt;Unfamiliarity increases the chance of incorrect prediction. Recovery is part of the design, not a later edge case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evidence
&lt;/h3&gt;

&lt;p&gt;What did people actually do?&lt;/p&gt;

&lt;p&gt;Ask participants what they think will happen before they act. Watch for hesitation, repeated scanning, accidental activation, Back behavior, abandonment, and recovery. Compare completion time and error patterns against the conventional alternative. Test with people who did not sit through the design process.&lt;/p&gt;

&lt;p&gt;The most revealing question is often not "Do you like it?" It is "What would you do next, and what do you expect to happen?"&lt;/p&gt;

&lt;p&gt;Preference can reward visual novelty. Prediction reveals whether the interaction has become understandable.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Review for Design and Engineering Teams
&lt;/h2&gt;

&lt;p&gt;The familiar-versus-novel decision should not live only in a design critique. It affects implementation, content, accessibility, analytics, and support.&lt;/p&gt;

&lt;p&gt;Before committing to an unfamiliar pattern, I would ask the team to review it from five angles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Product:&lt;/strong&gt; What user problem requires a different interaction?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design:&lt;/strong&gt; Which existing mental model are we preserving, extending, or replacing?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engineering:&lt;/strong&gt; What additional state, feedback, fallback, and recovery does the new behavior require?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility:&lt;/strong&gt; Can the same intent be perceived and operated through keyboard, touch, zoom, and assistive technology?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Research:&lt;/strong&gt; What observation would cause us to revise or remove the pattern?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This review changes the conversation. Instead of debating whether a concept is exciting or boring, the team discusses where the interaction spends attention and what return it creates.&lt;/p&gt;

&lt;p&gt;It also makes implementation more honest. Novel interactions are rarely just a front-end flourish. They create new states, new explanations, new failure modes, and new testing responsibilities. If the team is unwilling to fund those responsibilities, it has not funded the interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Familiar Core, Novel Edge Principle
&lt;/h2&gt;

&lt;p&gt;The strongest balance I have found is a familiar core with a novel edge.&lt;/p&gt;

&lt;p&gt;The familiar core helps people enter, navigate, understand state, perform common actions, and recover. The novel edge gives the product its particular advantage, expression, or way of working. It is noticeable because the rest of the interface is not competing for the same attention.&lt;/p&gt;

&lt;p&gt;That balance is especially important as interfaces absorb AI-generated suggestions, autonomous actions, spatial tools, richer collaboration, and more adaptive behavior. New capability will require new patterns. It does not require us to discard every convention around those patterns.&lt;/p&gt;

&lt;p&gt;An AI system can propose a new kind of plan while still using familiar approval controls. A design tool can introduce a new manipulation model while preserving undo and visible selection. A research experience can invite exploration while keeping location, progress, and exit clear.&lt;/p&gt;

&lt;p&gt;Innovation works better when users have somewhere stable to stand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Takeaway
&lt;/h2&gt;

&lt;p&gt;Familiarity is not the enemy of creativity. It is the infrastructure that lets creativity matter.&lt;/p&gt;

&lt;p&gt;Use conventions for the parts of an interface that should disappear into competence. Use novelty where the product creates a capability, expression, or experience worth learning. Separate visual originality from behavioral change. Protect high-risk tasks with predictable controls. Give unfamiliar patterns a familiar anchor, a durable benefit, safe recovery, and evidence.&lt;/p&gt;

&lt;p&gt;The goal is not to make every interface feel like everything that came before it. The goal is to avoid charging users for differences that do not improve their experience.&lt;/p&gt;

&lt;p&gt;Borrow the instincts people already have. Invent where the product has earned it.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Budiu, R. (2024, January 15). &lt;em&gt;&lt;a href="https://www.nngroup.com/articles/recognition-and-recall/" rel="noopener noreferrer"&gt;Memory recognition and recall in user interfaces&lt;/a&gt;.&lt;/em&gt; Nielsen Norman Group.&lt;/p&gt;

&lt;p&gt;Chan, M. (2024, January 26). &lt;em&gt;&lt;a href="https://www.nngroup.com/articles/mental-models/" rel="noopener noreferrer"&gt;Mental models and user experience design&lt;/a&gt;.&lt;/em&gt; Nielsen Norman Group.&lt;/p&gt;

&lt;p&gt;Budiu, R. (2016, October 30). &lt;em&gt;&lt;a href="https://www.nngroup.com/articles/power-law-learning/" rel="noopener noreferrer"&gt;The power law of learning: Consistency vs. innovation in user interfaces&lt;/a&gt;.&lt;/em&gt; Nielsen Norman Group.&lt;/p&gt;

&lt;p&gt;World Wide Web Consortium. (n.d.). &lt;em&gt;&lt;a href="https://www.w3.org/WAI/WCAG22/Understanding/consistent-navigation.html" rel="noopener noreferrer"&gt;Understanding Success Criterion 3.2.3: Consistent navigation&lt;/a&gt;.&lt;/em&gt; Web Accessibility Initiative.&lt;/p&gt;

&lt;p&gt;Zajonc, R. B. (1968). &lt;a href="https://doi.org/10.1037/h0025848" rel="noopener noreferrer"&gt;Attitudinal effects of mere exposure&lt;/a&gt;. &lt;em&gt;Journal of Personality and Social Psychology, 9&lt;/em&gt;(2, Pt. 2), 1-27.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;What is the difference between familiar and novel interface design?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Familiar interface design uses patterns people already recognize, which lowers learning and prediction costs. Novel interface design introduces a new visual, structural, or behavioral pattern. Novelty is most defensible when it enables a capability or experience that familiar patterns cannot express as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a novelty budget in UI/UX design?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A novelty budget is my way of treating unfamiliarity as a limited product resource. Every new interaction asks users to spend attention and learning effort. A team should reserve that cost for the parts of the product that create durable value and keep commodity tasks predictable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When should a designer break a familiar UI convention?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Break a convention when the existing pattern cannot support the product's core capability, repeated use will repay the learning cost, exploration is part of the task, or the new pattern creates useful differentiation. The change should still include clear feedback, recovery, accessibility, and evidence from user behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does following conventions make every product look the same?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Conventions define expectations about meaning and behavior, not a single visual style. Typography, composition, motion, imagery, pacing, and brand voice can create a distinct experience while navigation, forms, and recovery remain familiar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How can teams test an unfamiliar interaction?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ask users what they expect before they act, then observe hesitation, errors, recovery, abandonment, and repeated use. Compare the unfamiliar pattern with a conventional alternative. The FUSE test adds four gates: a familiar anchor, a meaningful user benefit, safe failure, and evidence.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>interactiondesign</category>
      <category>design</category>
      <category>userresearch</category>
    </item>
    <item>
      <title>Full Sail, Finished: We Did It</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Sat, 29 Aug 2026 14:31:14 +0000</pubDate>
      <link>https://dev.to/rverwey/full-sail-finished-we-did-it-4ia5</link>
      <guid>https://dev.to/rverwey/full-sail-finished-we-did-it-4ia5</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.ryanverwey.dev/blog/full-sail-web-development-program-reflection" rel="noopener noreferrer"&gt;ryanverwey.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Full Sail University's Web Development Bachelor of Science program changed how I build by forcing me to connect software decisions to product outcomes. It was not only a sequence of classes about HTML, CSS, JavaScript, APIs, databases, security, and deployment. It was a long pressure test of whether I could keep improving the way I plan, ship, explain, and maintain real web projects.&lt;/p&gt;

&lt;p&gt;I completed the Web Development Bachelor of Science degree at Full Sail University in July 2026. Along the way, I was named Valedictorian for the Web Development Degree Program, received Full Sail's Advanced Achievement Award, earned four Course Director's Awards, and was recognized by the National Society of Collegiate Scholars for scholarship, leadership, and service.&lt;/p&gt;

&lt;p&gt;Those distinctions matter to me, but not because they make the work complete by themselves. They matter because they reflect the same thing I was trying to build throughout the program: consistent execution, clear thinking, and the ability to turn a requirement into something real.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Earned
&lt;/h2&gt;

&lt;p&gt;The final academic outcome was straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bachelor of Science in Web Development from Full Sail University, awarded July 31, 2026.&lt;/li&gt;
&lt;li&gt;Valedictorian, Web Development Degree Program.&lt;/li&gt;
&lt;li&gt;Advanced Achievement Award, Web Development Degree Program.&lt;/li&gt;
&lt;li&gt;Course Director's Award for Server-Side Languages.&lt;/li&gt;
&lt;li&gt;Course Director's Award for Project and Portfolio III: Web Development.&lt;/li&gt;
&lt;li&gt;Course Director's Award for Project and Portfolio IV: Web Development.&lt;/li&gt;
&lt;li&gt;Course Director's Award for Project and Portfolio V: Web Development.&lt;/li&gt;
&lt;li&gt;National Society of Collegiate Scholars recognition for scholarship, leadership, and service, presented November 2, 2024.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The degree represents completion of the program. Valedictorian represents academic standing. The Advanced Achievement Award means more to me because it is broader than grades. Full Sail describes it as a graduating-class distinction tied to overall effort, dedication, energy, sacrifice, skill, leadership, and program-wide performance.&lt;/p&gt;

&lt;p&gt;The Course Director's Awards sit somewhere different. They are course-level recognition, and I am proud of where they landed. Server-Side Languages validated the backend work that helped push me from frontend implementation into application architecture. Project and Portfolio III, IV, and V validated the larger pattern I was trying to build: take what the program teaches, apply it under deadline pressure, and produce portfolio-grade work that can be explained after the assignment is over.&lt;/p&gt;

&lt;p&gt;I do not see any of these as participation awards. I see them as evidence that I showed up consistently, took the work seriously, and improved in ways that were visible to the instructors evaluating the work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Degree and Award Images
&lt;/h2&gt;

&lt;p&gt;The images below are the degree and award records behind the academic honors referenced in this reflection.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;img src="/images/blog/full-sail-bachelor-degree.webp" alt="Full Sail University Bachelor of Science degree awarded to Ryan VerWey for the Web Development Degree Program"&amp;gt;
&amp;lt;figcaption&amp;gt;
  Bachelor of Science, Web Development Degree Program
&amp;lt;/figcaption&amp;gt;



&amp;lt;img src="/images/blog/full-sail-valedictorian-award.webp" alt="Full Sail University Valedictorian certificate awarded to Ryan VerWey for the Web Development Degree Program"&amp;gt;
&amp;lt;figcaption&amp;gt;
  Valedictorian, Web Development Degree Program
&amp;lt;/figcaption&amp;gt;



&amp;lt;img src="/images/blog/full-sail-advanced-achievement-award.webp" alt="Full Sail University Advanced Achievement Award certificate awarded to Ryan VerWey for the Web Development Degree Program"&amp;gt;
&amp;lt;figcaption&amp;gt;
  Advanced Achievement Award, Web Development Degree Program
&amp;lt;/figcaption&amp;gt;



&amp;lt;img src="/images/blog/full-sail-course-director-server-side-languages.webp" alt="Full Sail University Course Director's Award certificate awarded to Ryan VerWey for Server-Side Languages"&amp;gt;
&amp;lt;figcaption&amp;gt;
  Course Director's Award, Server-Side Languages
&amp;lt;/figcaption&amp;gt;



&amp;lt;img src="/images/blog/full-sail-course-director-project-portfolio-3.webp" alt="Full Sail University Course Director's Award certificate awarded to Ryan VerWey for Project and Portfolio III Web Development"&amp;gt;
&amp;lt;figcaption&amp;gt;
  Course Director's Award, Project and Portfolio III
&amp;lt;/figcaption&amp;gt;



&amp;lt;img src="/images/blog/full-sail-course-director-project-portfolio-4.webp" alt="Full Sail University Course Director's Award certificate awarded to Ryan VerWey for Project and Portfolio IV Web Development"&amp;gt;
&amp;lt;figcaption&amp;gt;
  Course Director's Award, Project and Portfolio IV
&amp;lt;/figcaption&amp;gt;



&amp;lt;img src="/images/blog/full-sail-course-director-project-portfolio-5.webp" alt="Full Sail University Course Director's Award certificate awarded to Ryan VerWey for Project and Portfolio V Web Development"&amp;gt;
&amp;lt;figcaption&amp;gt;
  Course Director's Award, Project and Portfolio V
&amp;lt;/figcaption&amp;gt;



&amp;lt;img src="/images/blog/full-sail-nscs-scholarship-leadership-service.webp" alt="National Society of Collegiate Scholars recognition for Ryan VerWey for scholarship leadership and service at Full Sail University"&amp;gt;
&amp;lt;figcaption&amp;gt;
  National Society of Collegiate Scholars recognition
&amp;lt;/figcaption&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Program Was Not Just About Learning Syntax
&lt;/h2&gt;

&lt;p&gt;It is easy to describe a web development degree as a list of technologies. That would be accurate, but incomplete.&lt;/p&gt;

&lt;p&gt;The program did cover technical fundamentals. I worked through HTML structure, CSS layout, JavaScript logic, interface design, application state, backend routes, database models, authentication, deployment, testing, content management, security, and project delivery. Those topics matter. A web developer needs technical range.&lt;/p&gt;

&lt;p&gt;But the more valuable shift was how those topics started connecting.&lt;/p&gt;

&lt;p&gt;An interface is not separate from data modeling. A database decision affects the forms people use. Authentication affects the way a page should explain itself. Search engine optimization affects headings, routing, metadata, and content structure. Security affects input handling, deployment, secrets, and user trust. A portfolio is not just a gallery. It is a product surface that has to be usable, discoverable, credible, and maintainable.&lt;/p&gt;

&lt;p&gt;That was the real growth for me. I stopped seeing web development as a collection of isolated skills and started seeing it as a system of tradeoffs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Coming Into the Program With Real-World Pressure
&lt;/h2&gt;

&lt;p&gt;I did not experience Full Sail in a vacuum.&lt;/p&gt;

&lt;p&gt;I was already bringing a professional background into the program: military experience, geospatial intelligence work, contractor work, business ownership, team coordination, and the kind of operational habits that come from needing work to survive contact with real requirements. That background made the degree feel different.&lt;/p&gt;

&lt;p&gt;When a course asked for a user interface, I was thinking about whether a user could actually make a decision from it. When a course asked for backend logic, I was thinking about where the data came from, who trusted it, and what would happen if it failed. When a course asked for a deployment, I was thinking about environment variables, hosting behavior, search visibility, and whether I could repeat the process later.&lt;/p&gt;

&lt;p&gt;That professional context made school more valuable, not less. The assignments gave structure to things I had already started caring about. They forced me to slow down, name the decisions, and build a cleaner technical foundation underneath instincts I had picked up through work.&lt;/p&gt;

&lt;p&gt;Full Sail did not erase what I already knew. It gave me a more disciplined way to express it as web development.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Personal Cost Was Real
&lt;/h2&gt;

&lt;p&gt;The clean version of this story is easy to write: I earned the degree, finished with honors, built a stronger portfolio, and moved into a clearer developer path.&lt;/p&gt;

&lt;p&gt;That version is true, but it is not the whole truth.&lt;/p&gt;

&lt;p&gt;For most of the program, I was not just a student. I was working at least two jobs, raising children, trying to keep my household moving, and still carving out enough focus to finish assignments at a standard I could be proud of. There were plenty of weeks where school did not fit neatly into life. It had to be wedged into late nights, early mornings, lunch breaks, weekends, and whatever quiet space I could find between work and family responsibilities.&lt;/p&gt;

&lt;p&gt;That kind of pace takes a toll. It cost time. It cost rest. It cost energy I did not always have. At points, it cost pieces of my personal health because I kept choosing the long-term goal over short-term comfort. I do not want to romanticize that. Sacrifice sounds cleaner after the fact than it feels while you are living through it.&lt;/p&gt;

&lt;p&gt;There were days when the work felt heavier than the assignment in front of me. A project deadline was not just a project deadline. It was stacked on top of work pressure, parenting, finances, fatigue, and the constant mental load of trying not to drop anything important. Finishing the degree required more than technical ability. It required endurance.&lt;/p&gt;

&lt;p&gt;That is part of why the awards matter to me. They are not only academic decorations. They represent a period where I kept showing up while carrying a lot at once. They represent nights where I could have done the minimum and chose to push for better. They represent the discipline it took to build a new professional direction without being able to pause the rest of life.&lt;/p&gt;

&lt;p&gt;In the end, it was worth it because the program gave me more than a credential. It gave me the start of a new life and a real career path as a developer. It gave shape to work I already cared about. It gave me a portfolio, a stronger technical foundation, a clearer professional identity, and proof that I could keep building even when the circumstances were not easy.&lt;/p&gt;

&lt;p&gt;That is the part I will remember most.&lt;/p&gt;




&lt;h2&gt;
  
  
  Graduation Day
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdswcfctct277evwc4mzt.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdswcfctct277evwc4mzt.webp" alt="Ryan VerWey with family at Full Sail University graduation after completing the Web Development Bachelor of Science program" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Graduation day made the sacrifice feel visible. The degree was mine, but getting there was never only an individual effort. My family lived through the long schedule with me: the work hours, the school deadlines, the late nights, the stress, and the constant balancing act it took to keep everything moving.&lt;/p&gt;

&lt;p&gt;That picture matters because it shows what the program was really attached to. It was not just a career move on paper. It was a decision to build a different future while still being present for the people depending on me. That made the process harder, but it also made the outcome mean more.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Early Courses Built the Mental Model
&lt;/h2&gt;

&lt;p&gt;The first stretch of the program mattered because it established the mental model underneath everything else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ryanverwey.dev/blog/first-steps-into-webdev-fullsail" rel="noopener noreferrer"&gt;Introduction to Web Architecture&lt;/a&gt; made the browser feel less like a black box. HTML and CSS became structural tools instead of files that happened to make a page appear. &lt;a href="https://www.ryanverwey.dev/blog/interfaces-and-usability-fullsail" rel="noopener noreferrer"&gt;Interfaces and Usability&lt;/a&gt; pushed that further by making design feel less subjective. Layout, hierarchy, spacing, contrast, and responsive behavior became part of how a product communicates.&lt;/p&gt;

&lt;p&gt;The early JavaScript courses were where logic became more practical. Conditionals, loops, arrays, objects, functions, and classes are easy to describe academically. They become more meaningful when they start controlling actual behavior in the browser. The program gave me repetition there, and repetition matters. You do not become useful with JavaScript by watching someone else explain it. You become useful by writing it, breaking it, debugging it, and understanding why it broke.&lt;/p&gt;

&lt;p&gt;Those early courses did not produce my most advanced projects, but they made the later projects possible. They built the habits that make larger systems easier to reason about.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Portfolio Courses Changed the Standard
&lt;/h2&gt;

&lt;p&gt;The Project and Portfolio courses were the backbone of the program for me.&lt;/p&gt;

&lt;p&gt;Those courses changed the standard from "complete the assignment" to "produce something you can stand behind." That distinction matters. A normal class assignment can disappear after grading. A portfolio project has to explain what you can do.&lt;/p&gt;

&lt;p&gt;Project and Portfolio I helped pull the early fundamentals together. &lt;a href="https://www.ryanverwey.dev/blog/project-portfolio-2-fullsail" rel="noopener noreferrer"&gt;Project and Portfolio II&lt;/a&gt; pushed deeper into React, API integration, data, and application behavior. &lt;a href="https://www.ryanverwey.dev/blog/project-portfolio-3-fullsail" rel="noopener noreferrer"&gt;Project and Portfolio III&lt;/a&gt; was where a fuller application started to emerge through authentication, profiles, blog features, project boards, and sprint planning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ryanverwey.dev/blog/project-portfolio-4-fullsail" rel="noopener noreferrer"&gt;Project and Portfolio IV&lt;/a&gt; raised the bar again by requiring more serious attention to access control, audit trails, cloud services, deployment, discovery, and postmortem work. &lt;a href="https://www.ryanverwey.dev/blog/project-portfolio-5-fullsail" rel="noopener noreferrer"&gt;Project and Portfolio V&lt;/a&gt; and &lt;a href="https://www.ryanverwey.dev/blog/project-portfolio-6-fullsail" rel="noopener noreferrer"&gt;Project and Portfolio VI&lt;/a&gt; became the launch path for Our Heritage Kitchen, moving it from product idea to beta planning, launch planning, search engine optimization, analytics, maintenance documentation, and handoff.&lt;/p&gt;

&lt;p&gt;That sequence changed my expectations for my own work. By the end, I was not satisfied with a demo that technically loaded. I wanted clean user flows, readable content, meaningful metadata, deployment clarity, version history, maintainable structure, and enough written context that another person could understand what I built without a private walkthrough.&lt;/p&gt;

&lt;p&gt;That mindset now shows up across my &lt;a href="https://www.ryanverwey.dev/projects" rel="noopener noreferrer"&gt;project portfolio&lt;/a&gt;, especially in the way I present live products, case details, technical stacks, and business context.&lt;/p&gt;




&lt;h2&gt;
  
  
  Backend Work Made Me Think in Systems
&lt;/h2&gt;

&lt;p&gt;The backend courses were important because they moved me past interface-only thinking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ryanverwey.dev/blog/server-side-languages-fullsail" rel="noopener noreferrer"&gt;Server-Side Languages&lt;/a&gt; was one of the courses that stuck with me most. It helped make API design, routing, testing, MongoDB, Docker, and Node.js feel like part of ordinary product development. That Course Director's Award meant a lot because it marked a point where backend work was no longer just something sitting behind the interface. It became a core part of how I thought about building.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ryanverwey.dev/blog/advanced-server-side-languages-fullsail" rel="noopener noreferrer"&gt;Advanced Server-Side Languages&lt;/a&gt; expanded that by pushing cleaner API architecture, TypeScript patterns, Express structure, WebSockets, and better service thinking. &lt;a href="https://www.ryanverwey.dev/blog/database-systems-fullsail" rel="noopener noreferrer"&gt;Database Systems&lt;/a&gt; added another layer by making persistence, backups, permissions, and database operations more explicit.&lt;/p&gt;

&lt;p&gt;The practical lesson was simple: full-stack development is not frontend plus backend as separate piles of work. It is the ability to design the boundary between them.&lt;/p&gt;

&lt;p&gt;That boundary affects performance, validation, security, user experience, analytics, and maintainability. It affects how clearly a feature can be tested. It affects whether the next developer can understand what the system is doing. It affects whether the user sees a coherent product or a collection of technical compromises.&lt;/p&gt;

&lt;p&gt;Those courses strengthened the systems side of my work, and I still feel that influence when building tools, dashboards, design systems, and business-facing applications.&lt;/p&gt;




&lt;h2&gt;
  
  
  Security Changed How I Look at Ordinary Code
&lt;/h2&gt;

&lt;p&gt;The security-related coursework helped me become more skeptical in a useful way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.ryanverwey.dev/blog/app-integration-security-fullsail" rel="noopener noreferrer"&gt;Application Integration and Security&lt;/a&gt; introduced security pressure in a broader application context. &lt;a href="https://www.ryanverwey.dev/blog/secure-application-development-fullsail" rel="noopener noreferrer"&gt;Secure Application Development&lt;/a&gt; made it more direct: browser trust, cross-site request forgery, command injection, secrets management, JSON Web Tokens, deployment risk, and the responsibilities that continue after code leaves the local machine.&lt;/p&gt;

&lt;p&gt;I do not market myself as a dedicated cybersecurity specialist. That is not the point. The point is that a full-stack developer cannot treat security as someone else's future cleanup task. The developer is often the person deciding how input is handled, where secrets live, how authentication works, how routes change data, how tokens move, and how deployment environments are configured.&lt;/p&gt;

&lt;p&gt;That course changed the way I look at normal development decisions. When I see a request parameter, I think about validation. When I see a key or token, I think about storage and rotation. When I see a form that changes state, I think about intent. When I see a production deployment, I think about what the system is trusting.&lt;/p&gt;

&lt;p&gt;That is not glamorous, but it is professional.&lt;/p&gt;




&lt;h2&gt;
  
  
  Content, Discovery, and Presentation Became Part of the Work
&lt;/h2&gt;

&lt;p&gt;One of the more useful lessons from the later program was that software does not speak for itself.&lt;/p&gt;

&lt;p&gt;Developers sometimes want the code to be enough. It rarely is. A project needs to be explained. It needs a purpose, an audience, a clear interface, useful metadata, and enough documentation that someone can evaluate it quickly.&lt;/p&gt;

&lt;p&gt;That lesson has shaped this portfolio heavily. I care about search engine optimization, answer engine optimization, generative engine optimization, structured content, internal links, evidence, page hierarchy, and readable project summaries because discoverability is part of the work. If a recruiter, business owner, hiring manager, or AI search system cannot understand what a project demonstrates, then the project is not doing its job as a portfolio artifact.&lt;/p&gt;

&lt;p&gt;My Full Sail retrospectives became part of that process. Each article helped package a piece of the program into something searchable and explainable. The goal was not to turn schoolwork into filler content. The goal was to document growth in a way that connects coursework to real capability.&lt;/p&gt;

&lt;p&gt;That is why the &lt;a href="https://www.ryanverwey.dev/blog/full-sail" rel="noopener noreferrer"&gt;Full Sail University learning journal&lt;/a&gt; exists. It gives the program a narrative arc instead of leaving it as a line item on a resume.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Work Started Turning Into Real Products
&lt;/h2&gt;

&lt;p&gt;By the end of the program, the work was not confined to class deliverables.&lt;/p&gt;

&lt;p&gt;I was building and improving my own portfolio as a living system. I was building project pages that explain technical choices instead of just showing screenshots. I was writing articles that package decisions, constraints, and lessons learned. I was building tools through Echo Effect, experimenting with AI-assisted portfolio discovery, and turning design system work into something reusable.&lt;/p&gt;

&lt;p&gt;That matters because professional growth is not only measured by the complexity of the code. It is measured by whether the code becomes useful.&lt;/p&gt;

&lt;p&gt;Our Heritage Kitchen became a full product case study. CorvaUI became a design system direction with documentation and framework demos. Optimize became a website audit product focused on search, answer engine optimization, generative engine optimization, crawler access, accessibility, and prioritized repair planning. Rupert became a grounded AI assistant for helping visitors understand my portfolio. These projects are not all the same kind of work, but they share the same pattern: interface, logic, content, data, deployment, and communication all have to support the same outcome.&lt;/p&gt;

&lt;p&gt;That is what Full Sail helped reinforce. Build the thing, but also make it understandable. Make it work, but also make it maintainable. Finish the assignment, but turn the learning into a reusable professional asset.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Valedictorian Means to Me
&lt;/h2&gt;

&lt;p&gt;Valedictorian is easy to explain from the outside: highest academic standing in the program.&lt;/p&gt;

&lt;p&gt;From the inside, it feels more personal than that. It represents consistency. It means I kept the work moving across a long program while also carrying real life, real professional pressure, and a growing set of projects outside the classroom.&lt;/p&gt;

&lt;p&gt;I am proud of the academic result, but I am more proud of the pattern behind it. Showing up every week matters. Reading the requirements carefully matters. Asking whether the work is actually good matters. Taking feedback seriously matters. Revising things that technically pass but do not meet your own standard matters.&lt;/p&gt;

&lt;p&gt;That is the part I want people to understand when they see the word Valedictorian on my profile. It is not just a grade-point detail. It is shorthand for sustained execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Advanced Achievement Award Means to Me
&lt;/h2&gt;

&lt;p&gt;The Advanced Achievement Award means something different.&lt;/p&gt;

&lt;p&gt;Valedictorian is academic. The Advanced Achievement Award is broader. It recognizes the kind of student Full Sail views as standing out across the graduating class through performance, effort, leadership, skill, sacrifice, and the overall way they moved through the program.&lt;/p&gt;

&lt;p&gt;That matters because software work is rarely judged on one dimension. Good grades are valuable, but professional trust comes from more than grades. It comes from communication, ownership, judgment, follow-through, and the ability to keep making progress when a problem is messy.&lt;/p&gt;

&lt;p&gt;That is why this award hit differently for me. It felt like recognition of the whole pattern, not just the transcript. The late nights, the rewrites, the overbuilt first drafts, the cleaner second drafts, the projects that had to be shipped, the feedback I had to absorb, and the effort to keep raising the bar all counted.&lt;/p&gt;

&lt;p&gt;Receiving that award alongside Valedictorian and multiple Course Director's Awards made the end of the program feel complete in a way I did not expect.&lt;/p&gt;




&lt;h2&gt;
  
  
  Course Director's Awards Were Signals Along the Way
&lt;/h2&gt;

&lt;p&gt;The four Course Director's Awards gave me mile markers.&lt;/p&gt;

&lt;p&gt;Server-Side Languages showed that the backend side of the program had clicked. That course required more than making buttons respond. It required routes, requests, responses, data, tests, and a clearer understanding of how applications behave away from the browser.&lt;/p&gt;

&lt;p&gt;Project and Portfolio III showed that I could pull multiple disciplines into a real full-stack project. It was not just a technical checkpoint. It was a delivery checkpoint.&lt;/p&gt;

&lt;p&gt;Project and Portfolio IV showed that I could revise and mature a project through access control, audit trails, cloud services, deployment thinking, and postmortem reflection.&lt;/p&gt;

&lt;p&gt;Project and Portfolio V showed that I could move a larger product idea toward beta with business viability, metrics, compliance, security posture, versioning, release planning, and a stronger sense of product ownership.&lt;/p&gt;

&lt;p&gt;Those awards do not replace the work. They point back to it. They mark moments where the work was strong enough to stand out.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Full Sail Contributed to My Professional Growth
&lt;/h2&gt;

&lt;p&gt;The biggest professional change was not that I learned a few more frameworks.&lt;/p&gt;

&lt;p&gt;The biggest change was that I became more deliberate.&lt;/p&gt;

&lt;p&gt;I became more deliberate about requirements. I started reading the assignment, project brief, or business need as a product contract instead of a checklist. What does the user need to do? What does the system need to prove? What does the page need to communicate? What will be hard to maintain later?&lt;/p&gt;

&lt;p&gt;I became more deliberate about interfaces. A component is not just a styled block. It is a decision about hierarchy, state, accessibility, responsiveness, and user confidence.&lt;/p&gt;

&lt;p&gt;I became more deliberate about backend logic. An API is not just a route. It is a boundary where trust, validation, persistence, and errors have to be handled clearly.&lt;/p&gt;

&lt;p&gt;I became more deliberate about deployment. A deployed application is not finished if the environment is fragile, the metadata is weak, the handoff is unclear, or nobody can tell what changed.&lt;/p&gt;

&lt;p&gt;I became more deliberate about writing. The ability to explain technical work is part of the work. A project without context is harder to evaluate, harder to trust, and easier to misunderstand.&lt;/p&gt;

&lt;p&gt;That is the professional growth I value most. Full Sail gave me structure, deadlines, repetition, feedback, and a progression that pushed those habits into place.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Would Tell Someone Starting the Program
&lt;/h2&gt;

&lt;p&gt;If I were talking to someone starting the Full Sail Web Development program, I would tell them not to treat the degree like a checklist.&lt;/p&gt;

&lt;p&gt;The assignments matter, but the artifacts matter more. Every course can become something useful if you treat it as part of a larger portfolio. Write down what you learned. Keep the work. Improve it after the grade. Connect the course to a real project. Ask what the assignment is actually trying to teach, not just what needs to be submitted by Sunday night.&lt;/p&gt;

&lt;p&gt;I would also tell them to build more than the minimum. Not recklessly, and not at the cost of missing requirements, but enough that the work becomes yours. The best learning I got from the program happened when I stopped asking "what is enough to pass?" and started asking "what would make this worth showing?"&lt;/p&gt;

&lt;p&gt;That question changed everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Take Forward
&lt;/h2&gt;

&lt;p&gt;I take forward a clearer identity as a developer.&lt;/p&gt;

&lt;p&gt;I build full-stack products, design systems, AI-assisted tools, search-ready content, and business websites that need to work for real people. I care about interfaces, but I also care about the system behind them. I care about code, but I also care about whether the product can be found, understood, measured, and maintained.&lt;/p&gt;

&lt;p&gt;Full Sail did not create that identity from nothing. It sharpened it. It gave me a structured path to prove it over and over again, course by course, project by project.&lt;/p&gt;

&lt;p&gt;The final degree, Valedictorian honor, Advanced Achievement Award, Course Director's Awards, and National Society recognition are important because they document the outcome. But the more important result is practical: I left the program with a stronger standard for my own work.&lt;/p&gt;

&lt;p&gt;That standard is what I am carrying forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Few Acknowledgements
&lt;/h2&gt;

&lt;p&gt;I owe Rachel more than a quick thank-you line can cover.&lt;/p&gt;

&lt;p&gt;She carried the reality of this program with me, not just the idea of it. Every late night, every overloaded week, every deadline that landed on top of work and family life affected her too. She had to live with the schedule, the stress, the distracted evenings, the times I was physically home but mentally buried in code, documentation, deployments, or school requirements. Finishing this degree took effort from me, but it also took patience, grace, and sacrifice from her.&lt;/p&gt;

&lt;p&gt;Rachel believed in the version of my life I was trying to build even when the day-to-day version of it was not clean or easy. She encouraged me when I was exhausted, gave me room when I needed to focus, and kept standing beside me through a process that asked a lot from our family. This degree is part of my professional story, but she is part of why I was able to finish it.&lt;/p&gt;

&lt;p&gt;To Trinity and Alex, I hope one day this makes sense in a way that goes beyond seeing Dad on a laptop all the time.&lt;/p&gt;

&lt;p&gt;There were nights, weekends, and ordinary family moments where school had to take space. I know that mattered. I know there were times when I had to ask for quiet, steal time, or push through one more assignment instead of being as present as I wanted to be. That is one of the hardest parts to write honestly because the goal was always for our family, but the work sometimes pulled me away from the very people I was doing it for.&lt;/p&gt;

&lt;p&gt;I hope what you take from this is not that work should consume your life. I hope you see that hard things can be finished, that starting over professionally is possible, and that building a better future sometimes requires a season of sacrifice. I wanted you to see me finish. I wanted you to see that learning does not stop when you become an adult, a parent, or a provider. I wanted you to have proof that persistence can turn into something real.&lt;/p&gt;

&lt;p&gt;To my friends and family, thank you for the encouragement, the check-ins, the patience, and the belief.&lt;/p&gt;

&lt;p&gt;Support does not always look dramatic from the outside. Sometimes it is a message at the right time, a conversation that helps you reset, someone listening while you are frustrated, or someone reminding you that the work is worth finishing. Those moments mattered more than I probably said while I was in the middle of it. When life was crowded and the finish line still felt far away, encouragement helped keep the goal visible.&lt;/p&gt;

&lt;p&gt;I also want to thank my Full Sail instructors for the mentorship, feedback, pressure, and structure they brought into the program.&lt;/p&gt;

&lt;p&gt;The best instructors did more than grade submissions. They made the work feel connected to a professional standard. They pushed clarity. They rewarded effort, but they also expected execution. They treated projects like opportunities to think harder, communicate better, and build with more intent. Their feedback helped me see where an assignment could become a stronger product, where a technical choice needed a better explanation, and where "working" was not the same thing as being finished.&lt;/p&gt;

&lt;p&gt;That mentorship mattered. It helped me turn coursework into portfolio work, portfolio work into professional direction, and professional direction into a stronger sense of what I want to build next.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;What degree did Ryan VerWey earn from Full Sail University?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I earned a Bachelor of Science in Web Development from Full Sail University. The degree was awarded on July 31, 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What academic honors did Ryan VerWey receive at Full Sail University?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I was named Valedictorian for the Web Development Degree Program, received the Advanced Achievement Award, and earned Course Director's Awards in Server-Side Languages, Project and Portfolio III: Web Development, Project and Portfolio IV: Web Development, and Project and Portfolio V: Web Development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Full Sail's Advanced Achievement Award?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Advanced Achievement Award is a graduating-class distinction that recognizes a standout student across the full program. It is broader than grade-point average alone and reflects effort, dedication, energy, sacrifice, skill, leadership, and overall program performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a Course Director's Award at Full Sail University?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Course Director's Award is course-level recognition from Full Sail faculty for standout performance in a specific course. In my case, those awards came from Server-Side Languages and three Project and Portfolio courses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How did Full Sail contribute to Ryan VerWey's professional growth?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Full Sail helped connect technical skills to professional delivery. The program strengthened my work across frontend interfaces, backend logic, databases, security, deployment, testing, documentation, product planning, portfolio presentation, and search-ready content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does this reflection connect to the rest of Ryan VerWey's portfolio?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This reflection connects the Full Sail program to the broader portfolio. The course retrospectives live in my &lt;a href="https://www.ryanverwey.dev/blog/full-sail" rel="noopener noreferrer"&gt;Full Sail learning journal&lt;/a&gt;, and the applied project work is collected on my &lt;a href="https://www.ryanverwey.dev/projects" rel="noopener noreferrer"&gt;projects page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;p&gt;This post closes out my &lt;a href="https://www.ryanverwey.dev/blog/full-sail" rel="noopener noreferrer"&gt;Full Sail University learning journal&lt;/a&gt;. For course-level detail, start with &lt;a href="https://www.ryanverwey.dev/blog/first-steps-into-webdev-fullsail" rel="noopener noreferrer"&gt;First Steps into Web Development&lt;/a&gt;, then follow the sequence through &lt;a href="https://www.ryanverwey.dev/blog/server-side-languages-fullsail" rel="noopener noreferrer"&gt;Server-Side Languages&lt;/a&gt;, &lt;a href="https://www.ryanverwey.dev/blog/secure-application-development-fullsail" rel="noopener noreferrer"&gt;Secure Application Development&lt;/a&gt;, &lt;a href="https://www.ryanverwey.dev/blog/project-portfolio-5-fullsail" rel="noopener noreferrer"&gt;Project and Portfolio V&lt;/a&gt;, and &lt;a href="https://www.ryanverwey.dev/blog/project-portfolio-6-fullsail" rel="noopener noreferrer"&gt;Project and Portfolio VI&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>education</category>
      <category>webdev</category>
      <category>portfolio</category>
      <category>professionalgrowth</category>
    </item>
    <item>
      <title>Turning GitHub Language Stats Into a Profile Snapshot</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 25 Aug 2026 14:44:39 +0000</pubDate>
      <link>https://dev.to/rverwey/turning-github-language-stats-into-a-profile-snapshot-2hlp</link>
      <guid>https://dev.to/rverwey/turning-github-language-stats-into-a-profile-snapshot-2hlp</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.ryanverwey.dev/blog/github-profile-language-metrics-python-action" rel="noopener noreferrer"&gt;ryanverwey.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/RyanVerWey/profile-language-metrics" rel="noopener noreferrer"&gt;profile-language-metrics&lt;/a&gt; as a reusable GitHub Action that generates a clean language snapshot for a GitHub profile README. It is written in Python, runs on GitHub Actions, scans active repositories, estimates non-empty source lines by language, and writes a polished SVG that can be embedded directly into a profile page.&lt;/p&gt;

&lt;p&gt;The short version: it is a vanity metric, but it is an honest one. It does not pretend to measure engineering value, productivity, or skill level by itself. It gives developers a lightweight way to show the shape of their public work, and it gives me another practical Python automation project that solves a real presentation problem.&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%2Finw7ld830qaflw6ze5ag.webp" 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%2Finw7ld830qaflw6ze5ag.webp" alt="Cover graphic for profile-language-metrics showing a Python-built GitHub Action release and current public language snapshot" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Built It
&lt;/h2&gt;

&lt;p&gt;GitHub profile READMEs are weirdly useful.&lt;/p&gt;

&lt;p&gt;They are part portfolio, part landing page, part proof-of-work surface. A good profile does not need to be loud, but it should give someone a fast read on what you build, what tools you use, and whether your work is active.&lt;/p&gt;

&lt;p&gt;The problem is that most profile widgets either depend on a third-party service, show generic GitHub stats that everyone has already seen, or turn into visual noise. I wanted something smaller and more specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a card that shows the language mix across my repos&lt;/li&gt;
&lt;li&gt;a scheduled workflow that keeps it updated&lt;/li&gt;
&lt;li&gt;no hosted dashboard&lt;/li&gt;
&lt;li&gt;no package install step&lt;/li&gt;
&lt;li&gt;no private repository names exposed&lt;/li&gt;
&lt;li&gt;a result that looks good embedded in Markdown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That made Python the right tool for the job. The project needed file walking, API calls, subprocess control, counters, text escaping, and SVG generation. None of that required a framework. It needed boring reliability more than a big dependency tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Action Generates
&lt;/h2&gt;

&lt;p&gt;The current public run against my GitHub profile found 40,292 estimated non-empty source lines across 17 public active repositories. Python shows up with 3,171 lines in that snapshot, alongside TypeScript, JavaScript, CSS, HTML, Astro, Svelte, Vue, YAML, MDX, Shell, Batchfile, and TOML.&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%2Fci6dwgnchtak9r1kjb3r.webp" 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%2Fci6dwgnchtak9r1kjb3r.webp" alt="Generated profile-language-metrics result card showing language totals across Ryan VerWey public GitHub repositories" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output is intentionally simple: one SVG card with a total line count, active repository count, stacked language distribution, and per-language rows. It is built for a README, not a business intelligence dashboard.&lt;/p&gt;

&lt;p&gt;That distinction matters. Line counts can be useful context, but they are not proof of seniority or quality. The value here is presentation: it turns scattered repository activity into a compact snapshot someone can understand in a few seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The action follows a predictable pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch eligible repositories from the GitHub API.&lt;/li&gt;
&lt;li&gt;Create a temporary, shallow, read-only checkout of each active repository inside the GitHub Actions runner.&lt;/li&gt;
&lt;li&gt;Walk source files and map extensions to languages.&lt;/li&gt;
&lt;li&gt;Count non-empty source lines.&lt;/li&gt;
&lt;li&gt;Render the aggregated result into an SVG.&lt;/li&gt;
&lt;li&gt;Let the profile workflow commit the generated file.&lt;/li&gt;
&lt;/ol&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%2Fjz951hypk3s9jjot95lf.webp" 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%2Fjz951hypk3s9jjot95lf.webp" alt="Workflow graphic showing profile-language-metrics fetching repos, using temporary GitHub Actions checkouts, counting source, and rendering SVG output" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That clone step deserves plain-English context. The action is not sending your repository to a third-party server, creating a permanent mirror, or changing your project files. It runs inside your own GitHub Actions job, performs a depth-1 checkout in a temporary runner workspace, reads the files for counting, and lets that workspace disappear when the job finishes. The only file the example workflow writes back is the generated &lt;code&gt;assets/language-metrics.svg&lt;/code&gt; in the profile repository where you installed the action.&lt;/p&gt;

&lt;p&gt;The repo filtering is as important as the counting. The action skips forks, archived repos, disabled repos, profile repos, dependency folders, build output, lockfiles, minified files, and binaries. Without those exclusions, the output gets polluted fast.&lt;/p&gt;

&lt;p&gt;The counting logic is deliberately conservative. It estimates non-empty source lines in recognized source files. It does not try to parse abstract syntax trees, classify generated code perfectly, or become a compliance-grade code inventory tool.&lt;/p&gt;

&lt;p&gt;That restraint is part of the design. For a profile README, I would rather have a clear, repeatable estimate than a complex analysis system that feels more official than it really is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Python Was the Right Fit
&lt;/h2&gt;

&lt;p&gt;This is the kind of Python I like writing: practical automation that sits between services, files, and developer workflow.&lt;/p&gt;

&lt;p&gt;The script has to do several jobs cleanly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;call GitHub's API with optional authentication&lt;/li&gt;
&lt;li&gt;handle public-only and private-inclusive modes&lt;/li&gt;
&lt;li&gt;create temporary repository checkouts without mutating source repositories or leaking private paths into logs&lt;/li&gt;
&lt;li&gt;skip binary and generated files&lt;/li&gt;
&lt;li&gt;count text safely with encoding fallbacks&lt;/li&gt;
&lt;li&gt;aggregate language totals with &lt;code&gt;Counter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;escape SVG text correctly&lt;/li&gt;
&lt;li&gt;write an output file that works in GitHub Markdown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation stays dependency-free. It uses Python's standard library plus Git on the runner. That makes the action easier to trust because the user does not have to wait on &lt;code&gt;npm install&lt;/code&gt;, audit a package tree, or wonder why a profile utility needs a heavy runtime.&lt;/p&gt;

&lt;p&gt;Here is the kind of workflow a user can drop into a profile repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate language metrics&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;37&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;8&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RyanVerWey/profile-language-metrics@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github_user_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ github.repository_owner }}&lt;/span&gt;
          &lt;span class="na"&gt;output_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;assets/language-metrics.svg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the user experience I wanted: configure it once, run it manually when you want the first image, then let the scheduled workflow keep it current.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Privacy Model
&lt;/h2&gt;

&lt;p&gt;Private repository support needed a clear boundary.&lt;/p&gt;

&lt;p&gt;The action can include private repositories when the caller supplies a token with the right access, but the generated SVG only shows aggregate totals. It does not write private repository names, URLs, or per-repo breakdowns into the image.&lt;/p&gt;

&lt;p&gt;That tradeoff is intentional. A developer might want their private work represented in the overall language mix, but a profile README is still public. Aggregates are useful. Private project disclosure is not.&lt;/p&gt;

&lt;p&gt;I also suppress clone command output when a token is present and disable Git Large File Storage smudge during clone. That keeps logs cleaner and avoids pulling large private assets that do not belong in a lightweight metrics run.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Shows About My Python Work
&lt;/h2&gt;

&lt;p&gt;This project is not Python for Python's sake. It is Python used where Python makes the product simpler.&lt;/p&gt;

&lt;p&gt;The code has to be comfortable with API boundaries, local file systems, subprocesses, temporary workspaces, string rendering, escaping, and operational edge cases. It also has to be packaged so another developer can use it without reading the entire implementation first.&lt;/p&gt;

&lt;p&gt;That is the part I care about most: turning a script into a reusable tool.&lt;/p&gt;

&lt;p&gt;A one-off script would have been easy. A release needs more discipline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clear inputs&lt;/li&gt;
&lt;li&gt;documented outputs&lt;/li&gt;
&lt;li&gt;safe defaults&lt;/li&gt;
&lt;li&gt;exclusion rules&lt;/li&gt;
&lt;li&gt;read-only private token guidance&lt;/li&gt;
&lt;li&gt;a license&lt;/li&gt;
&lt;li&gt;attribution notes&lt;/li&gt;
&lt;li&gt;a README that gets someone from zero to embedded SVG&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the difference between "I wrote some Python" and "I shipped a Python-based developer tool people can use."&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Improve Next
&lt;/h2&gt;

&lt;p&gt;The release is useful now, but there are a few improvements I would consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adding more language extensions as edge cases appear&lt;/li&gt;
&lt;li&gt;improving the stacked bar renderer for very small language segments&lt;/li&gt;
&lt;li&gt;offering a compact card variant for narrower profile layouts&lt;/li&gt;
&lt;li&gt;adding a JSON output for people who want to build their own visualization&lt;/li&gt;
&lt;li&gt;documenting a few example profile README layouts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would still keep the core small. This kind of project gets worse if it tries to become a full analytics platform. The point is a clean profile snapshot, not an enterprise code intelligence system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;The project is public here: &lt;a href="https://github.com/RyanVerWey/profile-language-metrics" rel="noopener noreferrer"&gt;RyanVerWey/profile-language-metrics&lt;/a&gt;. If you like the release or end up using it in your own profile README, star the repo. That signal helps the project reach other developers who want a clean GitHub vanity snapshot without depending on a hosted badge service.&lt;/p&gt;

&lt;p&gt;If you want a profile README card that shows your language mix without relying on a hosted badge service, add the action to your profile repository and let GitHub Actions commit the SVG. It is small, readable, MIT licensed, and built to be easy to understand.&lt;/p&gt;

&lt;p&gt;For more context on the kind of developer work I build and publish, see my &lt;a href="https://www.ryanverwey.dev/projects" rel="noopener noreferrer"&gt;projects&lt;/a&gt; and &lt;a href="https://www.ryanverwey.dev/about" rel="noopener noreferrer"&gt;about page&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;What is profile-language-metrics?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;profile-language-metrics is a reusable GitHub Action that generates a profile-ready SVG showing aggregate source-line estimates by programming language across active repositories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this a serious engineering metric?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. It is a useful profile visualization, not a measurement of engineering quality, productivity, or business impact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why did you build it in Python?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Python fit the job: API requests, file walking, subprocess calls, counters, text escaping, and SVG rendering without pulling in a package install step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can it include private repositories?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, if the caller supplies a token with access. Private repositories are shown only as aggregate totals, not as names, URLs, or per-repository details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who should use it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers who want a clean GitHub profile README language snapshot that updates on a schedule and stays under their own repository control.&lt;/p&gt;

</description>
      <category>python</category>
      <category>githubactions</category>
      <category>automation</category>
      <category>svg</category>
    </item>
    <item>
      <title>Publish First, Syndicate Later: Automating Dev.to Without Losing SEO Credit</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Fri, 21 Aug 2026 14:43:05 +0000</pubDate>
      <link>https://dev.to/rverwey/publish-first-syndicate-later-automating-devto-without-losing-seo-credit-4akm</link>
      <guid>https://dev.to/rverwey/publish-first-syndicate-later-automating-devto-without-losing-seo-credit-4akm</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.ryanverwey.dev/blog/automate-nextjs-blog-devto-canonical-delay" rel="noopener noreferrer"&gt;ryanverwey.dev&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you publish articles on a Next.js portfolio or agency website, Dev.to can be a useful syndication channel. You get distribution in a developer community, another place for people to discover your work, and a canonical backlink pointing to the original article on your own domain.&lt;/p&gt;

&lt;p&gt;The important part is order.&lt;/p&gt;

&lt;p&gt;Publish on your website first. Give search engines time to crawl your original page. Then publish the Dev.to copy with a canonical URL that points back to your site. That is how you use syndication for reach without teaching Google that the copy is the source of truth.&lt;/p&gt;

&lt;p&gt;This guide walks through a practical setup: a Next.js blog, an RSS feed or local Markdown files, a Dev.to API key stored as a GitHub secret, a daily GitHub Actions workflow, and a script that waits three days before posting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Publish the original post on your own domain, wait three days, then post the Dev.to copy with &lt;code&gt;canonical_url&lt;/code&gt; set to your original URL. Include the cover image, convert body images to absolute URLs, and send no more than four Dev.to tags.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Syndicate to Dev.to at All?
&lt;/h2&gt;

&lt;p&gt;Your portfolio blog is the source of truth. That is where you own the domain, the analytics, the internal links, the service pages, the calls to action, and the long-term SEO value.&lt;/p&gt;

&lt;p&gt;Dev.to is different. It is a discovery channel.&lt;/p&gt;

&lt;p&gt;When you syndicate correctly, Dev.to can help with:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Getting technical articles in front of readers who may never find your personal site first.&lt;/li&gt;
&lt;li&gt;Creating a clean attribution path from a high-authority community platform back to your original post.&lt;/li&gt;
&lt;li&gt;Building repeatable distribution without manually copying every article.&lt;/li&gt;
&lt;li&gt;Keeping your writing workflow centered on your own website, not on rented platforms.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The danger is duplicate content confusion. If the same article appears on your site and on Dev.to at the same time, Google has to decide which URL represents the original. Google recommends using canonical links in the HTML head and using absolute URLs for canonical annotations. DEV also documents a canonical URL field for imported or manually created posts, specifically so the original source can keep SEO credit.&lt;/p&gt;

&lt;p&gt;That is why the delay matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Three-Day Delay Does
&lt;/h2&gt;

&lt;p&gt;A three-day delay is not a magic ranking switch. It is a practical buffer.&lt;/p&gt;

&lt;p&gt;When a new article goes live on your portfolio, you want search engines to see your domain first. The delay gives you time to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy the post.&lt;/li&gt;
&lt;li&gt;Confirm the article URL returns &lt;code&gt;200&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm the canonical tag on your site points to itself.&lt;/li&gt;
&lt;li&gt;Let your sitemap, RSS feed, and internal links expose the original before Dev.to sees the copy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After that delay, the Dev.to version should point back to the original with &lt;code&gt;canonical_url&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Think of the Dev.to article as a syndicated copy with a signpost. The signpost says, "This is useful here, but the original lives over there."&lt;/p&gt;

&lt;p&gt;For high-priority posts, you can also request indexing in Google Search Console. Treat that as an acceleration option, not as a required step in the recurring automation.&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%2Fkcy8ru7zm2xeix8326dh.webp" 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%2Fkcy8ru7zm2xeix8326dh.webp" alt="Canonical syndication timeline showing original publication, sitemap discovery, crawler review, a three-day delay window, and the syndicated copy pointing back to the source article" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Are Building
&lt;/h2&gt;

&lt;p&gt;The automation has six parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Next.js blog source, usually Markdown or MDX files.&lt;/li&gt;
&lt;li&gt;A canonical URL for every article on your own domain.&lt;/li&gt;
&lt;li&gt;An RSS feed or script that can read each article's title, summary, body, date, image, and tags.&lt;/li&gt;
&lt;li&gt;A Dev.to API key stored outside your repo.&lt;/li&gt;
&lt;li&gt;A sync script that publishes only eligible posts.&lt;/li&gt;
&lt;li&gt;A scheduled GitHub Actions workflow that runs daily.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The workflow should do this every time it runs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read all local blog posts.&lt;/li&gt;
&lt;li&gt;Skip posts newer than three days.&lt;/li&gt;
&lt;li&gt;Build the original URL from the post slug.&lt;/li&gt;
&lt;li&gt;Check Dev.to for an existing article with that canonical URL.&lt;/li&gt;
&lt;li&gt;Convert MDX or HTML-only content into Dev.to-friendly Markdown.&lt;/li&gt;
&lt;li&gt;Make images absolute so they work away from your website.&lt;/li&gt;
&lt;li&gt;Send up to four relevant Dev.to tags.&lt;/li&gt;
&lt;li&gt;Create the Dev.to article with &lt;code&gt;canonical_url&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&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%2Fjtbh4qni4m1o8ydioi5v.webp" 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%2Fjtbh4qni4m1o8ydioi5v.webp" alt="Dark-mode GitHub Actions style automation workflow showing content parsing, eligibility filtering, image URL conversion, tag normalization, secret-protected API publishing, and successful publication" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Confirm Your Next.js Blog Has Stable Slugs
&lt;/h2&gt;

&lt;p&gt;Most Next.js portfolio blogs use one file per post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;content/blog/my-article-slug.mdx
content/blog/another-article.mdx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The filename becomes the URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://www.yourdomain.com/blog/my-article-slug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you automate anything, make that contract reliable. Your script needs one predictable way to turn a file into a URL.&lt;/p&gt;

&lt;p&gt;For example:&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;SITE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fileName&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;\.&lt;/span&gt;&lt;span class="sr"&gt;mdx&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;$/&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canonicalUrl&lt;/span&gt; &lt;span class="o"&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;SITE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not use localhost URLs, preview deployment URLs, random query strings, or relative canonical paths. The canonical URL should be the final public article URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Add Self-Referential Canonical Tags on Your Site
&lt;/h2&gt;

&lt;p&gt;Every original article should include a canonical tag in the HTML head that points to itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://www.yourdomain.com/blog/my-article-slug"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Next.js App Router, this usually belongs in &lt;code&gt;generateMetadata&lt;/code&gt;:&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="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Metadata&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;next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PageProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="k"&gt;export&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;generateMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;PageProps&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Metadata&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;slug&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;params&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getBlogPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&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;canonical&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://www.yourdomain.com/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alternates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&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="nx"&gt;canonical&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="s1"&gt;article&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="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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;banner&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="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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="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="s1"&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;banner&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this matters: your own page should clearly say, "I am the canonical version." The Dev.to copy will later say the same thing from the other direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Make Your Blog Frontmatter Syndication-Ready
&lt;/h2&gt;

&lt;p&gt;Each post needs enough metadata to become a Dev.to article without manual cleanup.&lt;/p&gt;

&lt;p&gt;Use a frontmatter shape like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Improve&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Portfolio&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Website"&lt;/span&gt;
&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-08-18"&lt;/span&gt;
&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;practical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;guide&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;improving&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;portfolio&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;website&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;better&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;structure,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;speed,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;images,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;calls&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;action."&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Next.js"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SEO"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Portfolio"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Web&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Development"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Web&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Development"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;banner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/images/blog/example-cover.webp"&lt;/span&gt;
&lt;span class="na"&gt;updatedTime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-08-18"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key fields for Dev.to are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Becomes the Dev.to article title.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;summary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Becomes the Dev.to description.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;date&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Controls the three-day delay.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;banner&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Becomes the Dev.to &lt;code&gt;main_image&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tags&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Becomes Dev.to topic tags.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use a public image for &lt;code&gt;banner&lt;/code&gt;. Dev.to is not reading your site from the same origin, so a local image path like &lt;code&gt;/images/blog/cover.webp&lt;/code&gt; needs to be converted to &lt;code&gt;https://www.yourdomain.com/images/blog/cover.webp&lt;/code&gt; before publishing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Decide How Images Should Travel
&lt;/h2&gt;

&lt;p&gt;Images fail in syndication more often than text.&lt;/p&gt;

&lt;p&gt;There are two image types to handle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The article cover image.&lt;/li&gt;
&lt;li&gt;Images inside the article body.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the cover image, send Dev.to a public image URL:&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="nx"&gt;main_image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;absoluteUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For body images, convert local paths to absolute URLs before publishing:&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;makeImageUrlsAbsolute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;siteUrl&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;markdown&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;\\[&lt;/span&gt;&lt;span class="sr"&gt;([^&lt;/span&gt;&lt;span class="se"&gt;\\]&lt;/span&gt;&lt;span class="sr"&gt;]*&lt;/span&gt;&lt;span class="se"&gt;)\\&lt;/span&gt;&lt;span class="sr"&gt;]&lt;/span&gt;&lt;span class="se"&gt;\\((\\&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;\\&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&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="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`![&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;alt&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;siteUrl&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;src&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your posts use custom MDX components like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;BlogImage
  src="/images/blog/example.webp"
  alt="Dashboard on a laptop"
  caption="Use real images that explain the article."
/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Convert them before sending to Dev.to:&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;convertBlogImages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;siteUrl&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;markdown&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;/&amp;lt;BlogImage&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;s+&lt;/span&gt;&lt;span class="se"&gt;([^&lt;/span&gt;&lt;span class="sr"&gt;&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;?)\\&lt;/span&gt;&lt;span class="sr"&gt;s*&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="sr"&gt;/gs, &lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;_, attrs&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; =&amp;gt; &lt;/span&gt;&lt;span class="err"&gt;{
&lt;/span&gt;    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/src=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/alt=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;caption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/caption=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="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="nx"&gt;src&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imageUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&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;src&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;siteUrl&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&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;alt&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;imageUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;caption&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;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;n*&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;caption&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;image&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;Why this matters: the Dev.to API accepts Markdown. It does not understand your custom React components. Convert the content before it leaves your site.&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%2Fpw6vi89m9q3gfei0m7fm.webp" 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%2Fpw6vi89m9q3gfei0m7fm.webp" alt="Canonical signal matrix comparing the original portfolio article and the DEV.to syndicated copy across publishing order, canonical signals, image handling, topic tags, and failure modes" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Make Search Console Optional
&lt;/h2&gt;

&lt;p&gt;The normal workflow should not depend on a person submitting every URL by hand. Your automation should rely on stable article URLs, self-referential canonicals, a sitemap, internal links, RSS discovery, and the three-day Dev.to delay.&lt;/p&gt;

&lt;p&gt;For high-priority posts, request indexing for the original article as an optional acceleration step.&lt;/p&gt;

&lt;p&gt;Click-by-click:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://search.google.com/search-console" rel="noopener noreferrer"&gt;Google Search Console&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Select the property for your website.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;URL Inspection&lt;/strong&gt; search bar at the top.&lt;/li&gt;
&lt;li&gt;Paste the full original article URL.&lt;/li&gt;
&lt;li&gt;Press &lt;strong&gt;Enter&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Wait for Google to inspect the URL.&lt;/li&gt;
&lt;li&gt;If the page is live, click &lt;strong&gt;Request Indexing&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Wait for the confirmation message.&lt;/li&gt;
&lt;li&gt;Let the automated Dev.to workflow handle normal syndication after the three-day delay.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not required for Dev.to automation to work. It is useful when a post is especially important, timely, or tied to a campaign. For routine posts, let the automated workflow run without a manual Search Console task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Create a Dev.to API Key
&lt;/h2&gt;

&lt;p&gt;Do this from the Dev.to website:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to Dev.to.&lt;/li&gt;
&lt;li&gt;Click your profile image in the top-right corner.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Extensions&lt;/strong&gt; in the settings sidebar.&lt;/li&gt;
&lt;li&gt;Scroll to &lt;strong&gt;DEV Community API Keys&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Type a short label, such as &lt;code&gt;GitHub blog syndication&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Generate API Key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Copy the key once.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not paste the key into your source code. Do not commit it to GitHub. Do not put it in a public blog post, screenshot, issue, pull request, or README.&lt;/p&gt;

&lt;p&gt;The key belongs in your automation environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Store the API Key as a GitHub Secret
&lt;/h2&gt;

&lt;p&gt;If your portfolio is on GitHub, store the key as a repository secret:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your GitHub repository.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the left sidebar, click &lt;strong&gt;Secrets and variables&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Actions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New repository secret&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name the secret &lt;code&gt;DEVTO_API_KEY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Paste the Dev.to API key into the value field.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add secret&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your workflow will read it as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;DEVTO_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DEVTO_API_KEY }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That keeps the key out of your repo while still making it available to the scheduled job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Install the Packages Your Script Needs
&lt;/h2&gt;

&lt;p&gt;For an MDX or Markdown blog, a small Node script can usually do the job.&lt;/p&gt;

&lt;p&gt;Install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;gray-matter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already have &lt;code&gt;gray-matter&lt;/code&gt;, you can skip that. Node 18 and newer includes &lt;code&gt;fetch&lt;/code&gt;, so you do not need a separate HTTP client in most modern Next.js projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Add a Safe Tag Mapper
&lt;/h2&gt;

&lt;p&gt;Dev.to tags should be short, lowercase, and relevant. Most posts should use no more than four.&lt;/p&gt;

&lt;p&gt;Your website tags may be human-readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Web Development&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SEO&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Content Marketing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dev.to tags should look more like:&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="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;webdev&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;nextjs&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;seo&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;productivity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a mapper:&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;TAG_MAP&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;Web Development&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;webdev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;SEO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;seo&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;Content Marketing&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;contentmarketing&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;Web Design&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;webdesign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;JavaScript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Nextjs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nextjs&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeDevToTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tags&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;normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tags&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;tag&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;TAG_MAP&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&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;tag&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;tag&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="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;[^&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9&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="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="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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="nx"&gt;normalized&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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;Why this matters: tags are distribution channels on Dev.to. Bad tags make the article harder to discover, and too many tags can cause publishing problems. Keep the set focused.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10: Write the Sync Script
&lt;/h2&gt;

&lt;p&gt;Create a file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scripts/publish-devto.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a complete generic version you can adapt:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&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:path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;matter&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;gray-matter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SITE_URL&lt;/span&gt; &lt;span class="o"&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;SITE_URL&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEVTO_API_KEY&lt;/span&gt; &lt;span class="o"&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;DEVTO_API_KEY&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;BLOG_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&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="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content&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;blog&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;THREE_DAYS_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TAG_MAP&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;Web Development&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;webdev&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;Web Design&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;webdesign&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;SEO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;seo&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;Content Marketing&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;contentmarketing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;JavaScript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Nextjs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nextjs&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="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="nx"&gt;DEVTO_API_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing DEVTO_API_KEY.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;postSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileName&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;fileName&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;\.&lt;/span&gt;&lt;span class="sr"&gt;mdx&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;$/&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;canonicalForSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;SITE_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/blog/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&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;function&lt;/span&gt; &lt;span class="nf"&gt;absoluteUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&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;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://&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="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://&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="nx"&gt;url&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;SITE_URL&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&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="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;url&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;url&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="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeDevToTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tags&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;tag&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;TAG_MAP&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&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;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;tag&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="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;[^&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9&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="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="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&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="nx"&gt;normalized&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isAtLeastThreeDaysOld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&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;publishedTime&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;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;getTime&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="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isNaN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publishedTime&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;publishedTime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;THREE_DAYS_MS&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;convertBlogImages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&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;markdown&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;/&amp;lt;BlogImage&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;&amp;gt;&lt;/span&gt;&lt;span class="se"&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;&amp;gt;/g&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attrs&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;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/src=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/alt=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;caption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/caption=&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]([^&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)[&lt;/span&gt;&lt;span class="sr"&gt;"'&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)?.[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="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="nx"&gt;src&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="o"&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;alt&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="nf"&gt;absoluteUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;caption&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;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n*&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;caption&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;image&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeMarkdownPortable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&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="nf"&gt;convertBlogImages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdown&lt;/span&gt;&lt;span class="p"&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;\[([^\]]&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)\]\((\/[^&lt;/span&gt;&lt;span class="sr"&gt;)&lt;/span&gt;&lt;span class="se"&gt;]&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;src&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="nx"&gt;alt&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="nf"&gt;absoluteUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&amp;lt;Callout&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\s&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;&amp;gt; &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="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;*&amp;lt;&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;Callout&amp;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="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;devToRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://dev.to/api&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;endpoint&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="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&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="s1"&gt;api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DEVTO_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&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;application/json&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;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;{}),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="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="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&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;body&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Dev.to request failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&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="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;body&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;getExistingArticles&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;articles&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;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&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;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;devToRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/articles/me/all?page=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;per_page=100`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;articles&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="nx"&gt;batch&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;batch&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="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&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;articles&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;publishArticle&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;canonicalUrl&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="nf"&gt;devToRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/articles&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;article&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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&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="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body_markdown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;main_image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;absoluteUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;banner&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;canonical_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;canonicalUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;normalizeDevToTags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;published&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="p"&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&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;existingArticles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getExistingArticles&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;existingCanonicals&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;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingArticles&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;article&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;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;canonical_url&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="nb"&gt;Boolean&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;files&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="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BLOG_DIR&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;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;mdx&lt;/span&gt;&lt;span class="se"&gt;?&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;file&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;file&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;files&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;fullPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&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="nx"&gt;BLOG_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&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;slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;postSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&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;canonicalUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;canonicalForSlug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slug&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;source&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;fs&lt;/span&gt;&lt;span class="p"&gt;.&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;fullPath&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;matter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;source&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="nf"&gt;isAtLeastThreeDaysOld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Skipping &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: younger than three days.`&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existingCanonicals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;canonicalUrl&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Skipping &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: already syndicated.`&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;attribution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`*Originally published on [your portfolio](&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;canonicalUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;).*`&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;attribution&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;makeMarkdownPortable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;publishArticle&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;canonicalUrl&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;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Published &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;slug&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;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&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;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3500&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="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are four important safety checks in that script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It refuses to run without &lt;code&gt;DEVTO_API_KEY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It skips posts younger than three days.&lt;/li&gt;
&lt;li&gt;It checks existing Dev.to posts by &lt;code&gt;canonical_url&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It spaces out publish requests to avoid unnecessary API pressure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 11: Add Package Scripts
&lt;/h2&gt;

&lt;p&gt;Add scripts to &lt;code&gt;package.json&lt;/code&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;"scripts"&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;"publish:devto"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node scripts/publish-devto.mjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"publish:devto:dry-run"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node scripts/publish-devto.mjs --dry-run"&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;If you want a safer first version, add a dry-run mode before allowing writes. A dry run should print what would be published without calling &lt;code&gt;POST /articles&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run publish:devto:dry-run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script should print skipped and published posts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Skipping new-post: younger than three days.
Skipping old-post: already syndicated.
Published eligible-post: https://dev.to/username/eligible-post-slug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 12: Create the GitHub Actions Workflow
&lt;/h2&gt;

&lt;p&gt;Create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.github/workflows/devto-syndication.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a daily schedule plus a manual trigger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dev.to Syndication&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;25&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;13&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*'&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;syndicate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DEVTO_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DEVTO_API_KEY }}&lt;/span&gt;
      &lt;span class="na"&gt;SITE_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://www.yourdomain.com&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check out repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Node&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish eligible posts to Dev.to&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run publish:devto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cron time does not need to be exact. Pick a quiet time. The script controls eligibility, not the workflow schedule.&lt;/p&gt;

&lt;p&gt;Why daily works: a post published Monday at noon becomes eligible Thursday at noon. The next daily run after that will post it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 13: Test the Workflow Without Publishing
&lt;/h2&gt;

&lt;p&gt;Before publishing anything, test locally with a dry run or a temporary logging-only script.&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;New posts are skipped.&lt;/li&gt;
&lt;li&gt;Old posts are eligible.&lt;/li&gt;
&lt;li&gt;Existing Dev.to posts are skipped.&lt;/li&gt;
&lt;li&gt;Canonical URLs are absolute and correct.&lt;/li&gt;
&lt;li&gt;Cover images are absolute.&lt;/li&gt;
&lt;li&gt;Body images are absolute.&lt;/li&gt;
&lt;li&gt;Tags are lowercase and limited to four.&lt;/li&gt;
&lt;li&gt;No API key is printed in the logs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then run the GitHub Action manually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your GitHub repository.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Actions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Dev.to Syndication&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Run workflow&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose the branch.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Run workflow&lt;/strong&gt; again.&lt;/li&gt;
&lt;li&gt;Open the workflow run.&lt;/li&gt;
&lt;li&gt;Watch the log output.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The logs should show skipped or published posts, but never the API key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 14: Verify the Dev.to Article
&lt;/h2&gt;

&lt;p&gt;After the first publish, open the Dev.to article and check it manually.&lt;/p&gt;

&lt;p&gt;Confirm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The title is correct.&lt;/li&gt;
&lt;li&gt;The cover image appears.&lt;/li&gt;
&lt;li&gt;Body images appear.&lt;/li&gt;
&lt;li&gt;Code blocks are readable.&lt;/li&gt;
&lt;li&gt;Tables still make sense.&lt;/li&gt;
&lt;li&gt;The top attribution link points to the original post.&lt;/li&gt;
&lt;li&gt;The Dev.to canonical URL points to the original post.&lt;/li&gt;
&lt;li&gt;Tags are relevant and not spammy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you use the Dev.to editor, you can also check the canonical manually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the Dev.to post.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Edit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open the post settings.&lt;/li&gt;
&lt;li&gt;Find &lt;strong&gt;Canonical URL&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Confirm it matches your original article URL exactly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the basic Markdown editor, the same value may appear as frontmatter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;canonical_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://www.yourdomain.com/blog/my-article-slug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 15: Keep the Original URL Stable
&lt;/h2&gt;

&lt;p&gt;Canonical syndication depends on stable URLs.&lt;/p&gt;

&lt;p&gt;Avoid changing slugs after syndication. If you must change one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a permanent redirect from the old URL to the new URL.&lt;/li&gt;
&lt;li&gt;Update the Dev.to article's &lt;code&gt;canonical_url&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Update the attribution link.&lt;/li&gt;
&lt;li&gt;Re-submit the new original URL in Google Search Console.&lt;/li&gt;
&lt;li&gt;Confirm the old URL does not return a broken page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Broken canonical URLs waste the value of the whole setup. A canonical tag that points to a 404 is not helping the original article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 16: Build a Post-Publish Checklist
&lt;/h2&gt;

&lt;p&gt;Automation should reduce manual work, not remove responsibility.&lt;/p&gt;

&lt;p&gt;Use this automation-first checklist for every new article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Article is live on your own domain.&lt;/li&gt;
&lt;li&gt;[ ] Original page returns &lt;code&gt;200&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;[ ] Original page has a self-referential canonical URL.&lt;/li&gt;
&lt;li&gt;[ ] Original page has a usable title and meta description.&lt;/li&gt;
&lt;li&gt;[ ] Cover image is public and absolute.&lt;/li&gt;
&lt;li&gt;[ ] Body images are public or convertible to absolute URLs.&lt;/li&gt;
&lt;li&gt;[ ] Three days have passed.&lt;/li&gt;
&lt;li&gt;[ ] Dev.to copy includes &lt;code&gt;canonical_url&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;[ ] Dev.to copy includes the article image.&lt;/li&gt;
&lt;li&gt;[ ] Dev.to copy uses no more than four relevant tags.&lt;/li&gt;
&lt;li&gt;[ ] Dev.to copy includes attribution to the original post.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Optional for priority posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Google Search Console indexing request is submitted for the original URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Helps With Canonical Link Equity
&lt;/h2&gt;

&lt;p&gt;"Link juice" is casual SEO language for link equity, authority, or ranking signals that flow through links and canonical relationships. The phrase is imperfect, but the practical goal is clear: you want the original article on your domain to receive the strongest possible credit.&lt;/p&gt;

&lt;p&gt;The setup supports that goal in four ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your site publishes first.&lt;/li&gt;
&lt;li&gt;Your original page declares itself canonical.&lt;/li&gt;
&lt;li&gt;Dev.to declares your original page as canonical.&lt;/li&gt;
&lt;li&gt;The Dev.to body includes a visible attribution link back to the original.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Google still makes its own canonicalization decisions, and canonical tags are signals, not commands. But consistent signals matter. If your own page, your sitemap, your RSS feed, your Dev.to copy, and your internal links all point to the same original URL, you are making the decision easy for crawlers.&lt;/p&gt;

&lt;p&gt;That is the real purpose of the three-day delay. It gives the original article a head start before the high-authority duplicate appears.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Do not publish to Dev.to immediately.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Give your site time to be crawled first. Three days is a practical default.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not forget the canonical URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without &lt;code&gt;canonical_url&lt;/code&gt;, Dev.to may become the stronger version in search simply because the platform has more authority than your portfolio.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not use relative image paths.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dev.to cannot reliably render &lt;code&gt;/images/blog/example.webp&lt;/code&gt; unless it knows your domain. Convert it to &lt;code&gt;https://www.yourdomain.com/images/blog/example.webp&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not send every website tag to Dev.to.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pick four relevant tags. Treat tags like reader targeting, not keyword stuffing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not expose your API key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use GitHub Secrets, environment variables, or your deployment platform's secret manager.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do not rewrite internal links to Dev.to.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the goal is canonical value for your site, keep links pointing back to your original domain where appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual Fallback: RSS Import
&lt;/h2&gt;

&lt;p&gt;If you do not want to use the API yet, Dev.to also supports RSS imports.&lt;/p&gt;

&lt;p&gt;Click-by-click:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to Dev.to.&lt;/li&gt;
&lt;li&gt;Click your profile image.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Extensions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Find &lt;strong&gt;Publishing to DEV Community from RSS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste your RSS feed URL.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Mark the RSS source as canonical URL by default&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Save the feed settings.&lt;/li&gt;
&lt;li&gt;Review imported drafts before publishing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;RSS import is simpler. The API workflow gives you more control over the three-day delay, image conversion, existing-post checks, and tag mapping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Recommended Workflow
&lt;/h2&gt;

&lt;p&gt;For a Next.js portfolio, the cleanest process is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the blog post in your repo.&lt;/li&gt;
&lt;li&gt;Use an absolute cover image URL.&lt;/li&gt;
&lt;li&gt;Deploy the original post to your domain.&lt;/li&gt;
&lt;li&gt;Let the post sit for three days while your sitemap, feed, and internal links expose the original.&lt;/li&gt;
&lt;li&gt;Optionally request indexing in Google Search Console for priority posts.&lt;/li&gt;
&lt;li&gt;Run a scheduled GitHub Action every day.&lt;/li&gt;
&lt;li&gt;Have the script publish only eligible posts to Dev.to.&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;canonical_url&lt;/code&gt; with every Dev.to article.&lt;/li&gt;
&lt;li&gt;Include the main image and convert local body images.&lt;/li&gt;
&lt;li&gt;Limit Dev.to tags to four.&lt;/li&gt;
&lt;li&gt;Periodically audit Dev.to to make sure every syndicated article points back to the original.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is the balance: own the original, syndicate for reach, and make every duplicate point back to your domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;DEV Community Help, &lt;a href="https://dev.to/help/organizations/importing-your-organizations-content"&gt;"Importing Your Organization's Content"&lt;/a&gt;, accessed August 18, 2026.&lt;/li&gt;
&lt;li&gt;Forem API Docs, &lt;a href="https://developers.forem.com/api/v0#tag/articles/operation/createArticle" rel="noopener noreferrer"&gt;"Create a new article"&lt;/a&gt;, accessed August 18, 2026.&lt;/li&gt;
&lt;li&gt;Google Search Central, &lt;a href="https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls" rel="noopener noreferrer"&gt;"How to specify a canonical with rel=canonical and other methods"&lt;/a&gt;, accessed August 18, 2026.&lt;/li&gt;
&lt;li&gt;DEV Team, &lt;a href="https://dev.to/devteam/revamped-rss-feed-imports-3j1e"&gt;"Revamped RSS Feed Imports"&lt;/a&gt;, March 9, 2026.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>devto</category>
      <category>seo</category>
      <category>contentstrategy</category>
    </item>
    <item>
      <title>Social Media Content Calendar for Small Business Leads</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 18 Aug 2026 15:30:52 +0000</pubDate>
      <link>https://dev.to/rverwey/social-media-content-calendar-for-small-business-leads-1g2d</link>
      <guid>https://dev.to/rverwey/social-media-content-calendar-for-small-business-leads-1g2d</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.echoeffect.net/blog/social-media-content-calendar-small-business-leads-2026" rel="noopener noreferrer"&gt;echoeffect.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A social media content calendar should do more than remind you to post. For a small business, the useful version connects each post to an audience, a clear offer, a website destination, a tracking link, and a follow-up decision. That is how social media starts supporting leads instead of only producing likes.&lt;/p&gt;

&lt;p&gt;The short answer: plan one month at a time, publish consistently, send interested people to the right website page, tag links with campaign parameters, and review both platform insights and website traffic before changing the next month. Meta Business Suite can schedule Facebook and Instagram content and show paid and organic activity, while Google Analytics can identify campaigns that referred traffic to your site (Meta Business Help Center, n.d.-a; Google Analytics Help, n.d.-a).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaway:&lt;/strong&gt; A strong content calendar is a conversion system. Every planned post should have a business role: awareness, trust-building, traffic, lead capture, retention, or direct offer support.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Most Content Calendars Fail
&lt;/h2&gt;

&lt;p&gt;Most small business calendars fail because they start with empty dates instead of business goals. The owner asks, "What should we post on Tuesday?" instead of "What decision do we want a real customer to make this month?"&lt;/p&gt;

&lt;p&gt;That produces a familiar pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Random holidays that do not connect to the offer.&lt;/li&gt;
&lt;li&gt;Platform trends copied without a clear audience fit.&lt;/li&gt;
&lt;li&gt;Posts that get engagement but send nobody to the website.&lt;/li&gt;
&lt;li&gt;Links with no UTM tracking, so traffic becomes hard to attribute.&lt;/li&gt;
&lt;li&gt;No review cycle, so the same weak content repeats next month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A calendar is useful only when it reduces guesswork. For Echo Effect clients, that means connecting platform execution with the website, landing pages, service pages, analytics, and reporting. If your posts create interest but the website does not explain the next step, the calendar is doing only half the job.&lt;/p&gt;

&lt;p&gt;For deeper social execution, see Echo Effect's &lt;a href="https://dev.to/products/social-media"&gt;social media consulting services&lt;/a&gt;. If your website is the weak link after the click, review the &lt;a href="https://dev.to/products/web-design"&gt;web design and development services&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Should a Small Business Content Calendar Include?
&lt;/h2&gt;

&lt;p&gt;A practical social media content calendar should include the fields that affect publishing, measurement, and conversion. Keep it simple enough to use every week.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Calendar Field&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;Facebook, Instagram, LinkedIn, and X behave differently, so do not paste the same plan everywhere.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audience&lt;/td&gt;
&lt;td&gt;Name who the post is for: new prospects, warm leads, past customers, partners, or referral sources.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content role&lt;/td&gt;
&lt;td&gt;Label the post as awareness, education, proof, offer, event, retention, or community.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Format&lt;/td&gt;
&lt;td&gt;Choose the right asset: short video, carousel, static image, text post, story, article link, or poll.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Website destination&lt;/td&gt;
&lt;td&gt;Map the post to a service page, contact page, blog article, booking page, or landing page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracking link&lt;/td&gt;
&lt;td&gt;Use consistent UTM parameters so campaigns can be found in analytics.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owner and status&lt;/td&gt;
&lt;td&gt;Track draft, review, approved, scheduled, published, and measured.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Result&lt;/td&gt;
&lt;td&gt;Record useful outcomes: clicks, leads, comments, saves, replies, form starts, or booked calls.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Meta Business Suite supports creating and scheduling Facebook and Instagram posts from desktop, and its Insights area helps businesses understand paid and organic activity across a Facebook Page and Instagram account (Meta Business Help Center, n.d.-a; Meta Business Help Center, n.d.-b). That gives owners a starting point, but platform data should not be the only source of truth.&lt;/p&gt;

&lt;p&gt;Your website analytics matter because they show what happened after the click. Google Analytics describes the Traffic acquisition report as a way to understand where website and app visitors came from (Google Analytics Help, n.d.-b). If social media is meant to drive leads, then website sessions, engaged visits, form actions, and consultation requests deserve attention alongside reach and engagement.&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%2F0covca54iewe4yhnvwgf.webp" 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%2F0covca54iewe4yhnvwgf.webp" alt="Notebook page labeled marketing strategy beside a keyboard on a desk" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A content calendar works best when each post has a business role before it has a caption.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Build a Calendar That Drives Leads?
&lt;/h2&gt;

&lt;p&gt;Start with the offer, not the platform. If the business goal is consultation requests, the calendar should support the path from curiosity to contact.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Pick One Monthly Business Goal
&lt;/h3&gt;

&lt;p&gt;Choose one primary goal for the month:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;More consultation requests.&lt;/li&gt;
&lt;li&gt;More calls from a service page.&lt;/li&gt;
&lt;li&gt;More traffic to a new blog article.&lt;/li&gt;
&lt;li&gt;More quote requests for one service.&lt;/li&gt;
&lt;li&gt;More retargeting audience growth before a paid campaign.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One goal does not mean every post is promotional. It means every post has a job in the same customer journey. A contractor might spend the month educating homeowners about when a repair becomes urgent. A consultant might spend the month explaining one problem, showing proof of expertise, and sending prospects to a discovery call.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Map Content Roles Across the Month
&lt;/h3&gt;

&lt;p&gt;Use a balanced mix. A simple weekly rhythm might look like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Day&lt;/th&gt;
&lt;th&gt;Content Role&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monday&lt;/td&gt;
&lt;td&gt;Education&lt;/td&gt;
&lt;td&gt;Explain a common customer problem in plain language.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wednesday&lt;/td&gt;
&lt;td&gt;Proof&lt;/td&gt;
&lt;td&gt;Show a process, before-and-after context, or client-safe result without inventing claims.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Friday&lt;/td&gt;
&lt;td&gt;Offer&lt;/td&gt;
&lt;td&gt;Link to the relevant service page or consultation page.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weekend&lt;/td&gt;
&lt;td&gt;Community&lt;/td&gt;
&lt;td&gt;Ask a useful question, recap an event, or share a practical tip.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;LinkedIn's own Pages best practices frame a company page as a way to establish thought leadership, build brand awareness, and move an audience to action (LinkedIn Marketing Solutions, n.d.). That same principle applies across platforms: content should not only fill space, it should help the audience understand why the business is credible and what to do next.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Connect Posts to the Right Website Page
&lt;/h3&gt;

&lt;p&gt;Do not send every post to the homepage. Match the link to the intent.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A beginner education post can link to a blog article.&lt;/li&gt;
&lt;li&gt;A comparison post can link to a service page.&lt;/li&gt;
&lt;li&gt;A high-intent offer post can link to the contact page.&lt;/li&gt;
&lt;li&gt;A paid social campaign can link to a focused landing page.&lt;/li&gt;
&lt;li&gt;A trust-building post can link to an about page, review section, or case-study-style article if one exists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where social media and web development overlap. The calendar creates attention, but the website captures demand. If the website is slow, vague, hard to use on mobile, or missing a clear call to action, stronger posting will not fix the lead path. Pair this article with the &lt;a href="https://dev.to/blog/local-business-website-essentials"&gt;local business website essentials guide&lt;/a&gt; and the &lt;a href="https://dev.to/blog/core-web-vitals-small-business-checklist-2026"&gt;Core Web Vitals checklist&lt;/a&gt; when auditing the destination pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Use UTM Links Before You Publish
&lt;/h3&gt;

&lt;p&gt;UTM parameters are small pieces of text added to a URL so analytics tools can identify campaign traffic. Google's URL builder documentation explains that campaign parameters help identify campaigns that refer traffic (Google Analytics Help, n.d.-a).&lt;/p&gt;

&lt;p&gt;For a small business, keep naming consistent:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;UTM Field&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;utm_source&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;facebook&lt;/code&gt;, &lt;code&gt;instagram&lt;/code&gt;, &lt;code&gt;linkedin&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;utm_medium&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;organic_social&lt;/code&gt;, &lt;code&gt;paid_social&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;utm_campaign&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;august_2026_consultation_push&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;utm_content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;service_page_carousel&lt;/code&gt;, &lt;code&gt;owner_tip_video&lt;/code&gt;, &lt;code&gt;faq_post&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use lowercase names, avoid spaces, and document the pattern inside the calendar. The goal is not analytics perfection. The goal is to stop guessing whether social posts are creating website demand.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Review the Calendar Like a Sales Tool
&lt;/h3&gt;

&lt;p&gt;At the end of the month, do not ask only which post got the most likes. Ask better questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which posts drove qualified website traffic?&lt;/li&gt;
&lt;li&gt;Which links produced form starts, calls, bookings, or email inquiries?&lt;/li&gt;
&lt;li&gt;Which posts created real conversations with prospects?&lt;/li&gt;
&lt;li&gt;Which platform reached the best-fit audience?&lt;/li&gt;
&lt;li&gt;Which content role was missing?&lt;/li&gt;
&lt;li&gt;Which website page failed to move visitors forward?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Meta insights can help identify content performance on Facebook and Instagram, while Google Analytics can show acquisition patterns after people reach the website (Meta Business Help Center, n.d.-b; Google Analytics Help, n.d.-b). Neither system tells the whole story alone. Use both.&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%2Fgik9694j7ejoz4bn4kh1.webp" 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%2Fgik9694j7ejoz4bn4kh1.webp" alt="To-do list beside a laptop on a dark workspace" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The best calendar is simple enough to use weekly and specific enough to guide better decisions next month.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A 30-Day Content Calendar Framework
&lt;/h2&gt;

&lt;p&gt;Use this as a starter structure for one service line.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Week&lt;/th&gt;
&lt;th&gt;Focus&lt;/th&gt;
&lt;th&gt;Content Ideas&lt;/th&gt;
&lt;th&gt;Website Link&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Problem awareness&lt;/td&gt;
&lt;td&gt;Common mistakes, warning signs, myths, quick tips&lt;/td&gt;
&lt;td&gt;Educational blog article&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Trust and expertise&lt;/td&gt;
&lt;td&gt;Process explanation, FAQ, service comparison, behind-the-scenes workflow&lt;/td&gt;
&lt;td&gt;Service page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Proof and specificity&lt;/td&gt;
&lt;td&gt;Review-safe quote, project detail without private data, checklist, decision guide&lt;/td&gt;
&lt;td&gt;Related article or about page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Offer and conversion&lt;/td&gt;
&lt;td&gt;Consultation invitation, limited-scope audit, downloadable checklist, direct next step&lt;/td&gt;
&lt;td&gt;Contact page or landing page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This framework keeps the month balanced. It avoids a feed that is all selling and avoids a feed that is all education with no business outcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Metrics Should You Track?
&lt;/h2&gt;

&lt;p&gt;Track metrics in layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Useful Metrics&lt;/th&gt;
&lt;th&gt;What It Tells You&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Platform reach&lt;/td&gt;
&lt;td&gt;Reach, impressions, profile visits&lt;/td&gt;
&lt;td&gt;Did the post get seen by enough people?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform engagement&lt;/td&gt;
&lt;td&gt;Comments, saves, shares, replies, link clicks&lt;/td&gt;
&lt;td&gt;Did the topic create interest or action?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Website behavior&lt;/td&gt;
&lt;td&gt;Sessions, engaged sessions, landing page views&lt;/td&gt;
&lt;td&gt;Did the click become a real visit?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lead behavior&lt;/td&gt;
&lt;td&gt;Form submissions, calls, bookings, quote requests&lt;/td&gt;
&lt;td&gt;Did the visit create a business opportunity?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sales context&lt;/td&gt;
&lt;td&gt;Lead quality, close rate, common objections&lt;/td&gt;
&lt;td&gt;Did the content attract the right audience?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Vanity metrics are not useless, but they are incomplete. A post with modest reach and two qualified consultation requests can be more valuable than a viral post from people who will never buy.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Social Media Content Calendars for Small Businesses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How far ahead should a small business plan social media content?
&lt;/h3&gt;

&lt;p&gt;Plan one month at a time, then review weekly. Monthly planning gives enough structure for campaigns and approvals, while weekly review keeps the calendar flexible when offers, events, or customer questions change.&lt;/p&gt;

&lt;h3&gt;
  
  
  How often should a small business post?
&lt;/h3&gt;

&lt;p&gt;Posting frequency depends on the platform, audience, and internal capacity. A sustainable schedule that gets reviewed and improved is better than an aggressive schedule that collapses after two weeks. Start with three to five useful posts per week across your priority platforms, then adjust based on real engagement and lead quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should every post link to the website?
&lt;/h3&gt;

&lt;p&gt;No. Some posts should create trust, start conversations, or answer questions directly on the platform. But every calendar should include regular posts that send interested people to a relevant website page, especially when the goal is leads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need paid ads with a content calendar?
&lt;/h3&gt;

&lt;p&gt;Not always. Organic planning can improve consistency and clarify which messages resonate. Paid ads make more sense when the offer, website destination, audience, tracking, and creative have already been tested enough to spend with discipline.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the biggest content calendar mistake?
&lt;/h3&gt;

&lt;p&gt;The biggest mistake is planning posts without a measurement loop. If you do not review what created traffic, leads, conversations, and customer questions, the calendar becomes a publishing habit instead of a marketing system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can Echo Effect manage this for my business?
&lt;/h3&gt;

&lt;p&gt;Yes. Echo Effect's social media services include strategy, content creation, scheduling, platform optimization, reporting, and paid campaign support. The right fit depends on your goals, platforms, approval process, and whether your website is ready to convert visitors.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;A social media content calendar should make your marketing easier to run and easier to measure. The useful version connects posts to business goals, audience intent, website destinations, tracking links, and monthly decisions.&lt;/p&gt;

&lt;p&gt;If your business is posting inconsistently, relying on vanity metrics, or sending social traffic to weak website pages, Echo Effect can help build a cleaner system. Start with the &lt;a href="https://dev.to/products/social-media"&gt;social media consulting service&lt;/a&gt;, review your website's role in the funnel with &lt;a href="https://dev.to/products/web-design"&gt;web design and development&lt;/a&gt;, or &lt;a href="https://dev.to/contact"&gt;schedule a consultation&lt;/a&gt; to map the next 30 days around leads instead of guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Google Analytics Help. (n.d.-a). &lt;a href="https://support.google.com/analytics/answer/10917952?hl=en" rel="noopener noreferrer"&gt;URL builders: Collect campaign data with custom URLs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Google Analytics Help. (n.d.-b). &lt;a href="https://support.google.com/analytics/answer/12923437?hl=en" rel="noopener noreferrer"&gt;[GA4] Traffic acquisition report&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;LinkedIn Marketing Solutions. (n.d.). &lt;a href="https://business.linkedin.com/advertise/linkedin-pages/best-practices" rel="noopener noreferrer"&gt;LinkedIn Pages best practices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Meta Business Help Center. (n.d.-a). &lt;a href="https://www.facebook.com/business/help/942827662903020" rel="noopener noreferrer"&gt;Create and manage posts in Meta Business Suite on desktop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Meta Business Help Center. (n.d.-b). &lt;a href="https://www.facebook.com/business/help/700570830721044" rel="noopener noreferrer"&gt;About Insights in Meta Business Suite on desktop&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>socialmedia</category>
      <category>marketing</category>
      <category>contentmarketing</category>
      <category>business</category>
    </item>
    <item>
      <title>Website Accessibility Checklist for Small Businesses in 2026</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 18 Aug 2026 15:28:12 +0000</pubDate>
      <link>https://dev.to/rverwey/website-accessibility-checklist-for-small-businesses-in-2026-55lh</link>
      <guid>https://dev.to/rverwey/website-accessibility-checklist-for-small-businesses-in-2026-55lh</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.echoeffect.net/blog/website-accessibility-checklist-small-business-2026" rel="noopener noreferrer"&gt;echoeffect.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Website accessibility is not a side task for small business websites anymore. It affects whether people can read your content, use your forms, compare your services, request a quote, and trust your business.&lt;/p&gt;

&lt;p&gt;It also affects search visibility. Search engines and AI answer systems need clear text, useful headings, descriptive images, crawlable pages, and accurate structured data. Those are accessibility basics too.&lt;/p&gt;

&lt;p&gt;As of August 3, 2026, the practical benchmark for most small business website work is still WCAG 2.2, while W3C is actively developing WCAG 3.0 as the next major version of its accessibility guidance (W3C, 2023, 2026a). That does not mean every local business needs to become a legal expert. It means every business needs a repeatable accessibility review before design problems become customer problems.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Start with the customer journey. Make navigation, headings, text, images, forms, buttons, color contrast, keyboard access, and mobile layouts usable before chasing cosmetic design changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Accessibility Belongs in Your 2026 Website Plan
&lt;/h2&gt;

&lt;p&gt;An inaccessible website quietly blocks customers.&lt;/p&gt;

&lt;p&gt;A visitor may not be able to read low-contrast text. A keyboard user may not be able to open a menu. A screen reader user may not understand an image, button, form error, or service comparison. A mobile visitor may miss a call button because a sticky banner covers it. A person with a cognitive disability may abandon a confusing page before contacting the business.&lt;/p&gt;

&lt;p&gt;Those are not only compliance concerns. They are revenue concerns.&lt;/p&gt;

&lt;p&gt;The U.S. Department of Justice explains that inaccessible web content can deny people with disabilities equal access to communication, goods, services, programs, and activities. DOJ guidance also says businesses open to the public and state and local governments have ADA responsibilities related to accessible web content (U.S. Department of Justice, 2022).&lt;/p&gt;

&lt;p&gt;There is one important nuance. The 2024 DOJ web accessibility rule sets specific technical requirements for state and local governments under ADA Title II, not every private small business website. Still, the rule is a strong signal because it uses WCAG 2.1 Level AA as the required technical standard for covered public entities (U.S. Department of Justice, 2024). Private businesses should talk with qualified legal counsel about their specific obligations, but from a website quality standpoint, WCAG remains the most practical framework to follow.&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%2Fimages.unsplash.com%2Fphoto-1487014679447-9f8336841d58%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1487014679447-9f8336841d58%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Laptop showing a product website during a small business accessibility review" width="1200" height="693"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Accessibility work should be tied to real customer tasks: reading service details, comparing options, using forms, and contacting the business.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What WCAG 2.2 and WCAG 3 Mean for Small Businesses
&lt;/h2&gt;

&lt;p&gt;WCAG stands for Web Content Accessibility Guidelines. W3C says WCAG 2.2 covers recommendations for making web content more accessible to people with disabilities, including people with blindness, low vision, deafness, limited movement, cognitive limitations, and combinations of disabilities (W3C, 2023).&lt;/p&gt;

&lt;p&gt;WCAG 2.2 is the current stable recommendation. WCAG 3.0 is not final. W3C published an updated WCAG 3 Working Draft on March 3, 2026, and describes WCAG 3 as the future successor to the WCAG 2 series (W3C, 2026a, 2026b).&lt;/p&gt;

&lt;p&gt;For a small business owner, the takeaway is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use WCAG 2.2 as the practical checklist today.&lt;/li&gt;
&lt;li&gt;Do not wait for WCAG 3.0 to start fixing obvious barriers.&lt;/li&gt;
&lt;li&gt;Build habits that will age well: clear structure, readable design, usable forms, keyboard support, and tested customer journeys.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Good accessibility is not about passing a scan once. Automated scans are useful, but they cannot tell whether your offer is clear, whether your form error makes sense, or whether a person using a screen reader understands the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 Accessibility Checklist
&lt;/h2&gt;

&lt;p&gt;Use this checklist when reviewing a homepage, service page, contact page, quote form, landing page, or blog post.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Make the Page Structure Obvious
&lt;/h3&gt;

&lt;p&gt;A good page should make sense before anyone sees the colors or images.&lt;/p&gt;

&lt;p&gt;Check for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One clear H1 that describes the page.&lt;/li&gt;
&lt;li&gt;H2 sections that answer real customer questions.&lt;/li&gt;
&lt;li&gt;Short paragraphs that are easy to scan.&lt;/li&gt;
&lt;li&gt;Lists for steps, requirements, features, and comparisons.&lt;/li&gt;
&lt;li&gt;Internal links with descriptive anchor text.&lt;/li&gt;
&lt;li&gt;Page titles and meta descriptions that match the visible content.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This helps accessibility, SEO, AEO, and GEO at the same time. People skim headings. Search engines use structure to understand topics. AI answer systems need direct, well-labeled answers they can summarize without guessing.&lt;/p&gt;

&lt;p&gt;For example, a service page should answer "What do you do?", "Who is this for?", "What is included?", "How much does it usually involve?", "Where do you serve customers?", and "How do I contact you?" in visible text.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Write Alt Text for People First
&lt;/h3&gt;

&lt;p&gt;Alt text is not a keyword stuffing field. It is a text alternative for images that need one.&lt;/p&gt;

&lt;p&gt;Google's image SEO guidance says descriptive filenames, titles, and alt text help Google understand image subject matter, and that images should be placed near relevant text on relevant pages (Google Search Central, n.d.-a). W3C's image tutorial explains that informative image alternatives should convey the meaning or content shown visually, not merely list objects in the image (W3C, n.d.).&lt;/p&gt;

&lt;p&gt;Use this simple rule:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If an image explains something important, describe what matters.&lt;/li&gt;
&lt;li&gt;If an image is decorative, leave it empty or handle it as decorative in the code.&lt;/li&gt;
&lt;li&gt;If an image is a link or button, describe the action.&lt;/li&gt;
&lt;li&gt;If the image includes text, include the useful text in the page body whenever possible.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bad alt text: "SEO web design business accessibility 2026."&lt;/p&gt;

&lt;p&gt;Better alt text: "Customer using a laptop to review a small business service page."&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Use Color Contrast That Works in Real Life
&lt;/h3&gt;

&lt;p&gt;Low-contrast design is one of the fastest ways to make a website feel polished and unusable at the same time.&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Body text against the page background.&lt;/li&gt;
&lt;li&gt;Button text against button colors.&lt;/li&gt;
&lt;li&gt;Navigation links in hover and active states.&lt;/li&gt;
&lt;li&gt;Form labels, placeholders, helper text, and errors.&lt;/li&gt;
&lt;li&gt;Light text over images.&lt;/li&gt;
&lt;li&gt;Dark mode and light mode variants if the site supports both.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not rely on your own monitor. Test on a phone, in sunlight, at lower brightness, and with browser zoom. If the page gets harder to read, customers will feel it before they can explain it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Make Every Interactive Element Keyboard Usable
&lt;/h3&gt;

&lt;p&gt;Keyboard access is essential for people who cannot use a mouse, people using assistive technology, and power users who navigate quickly.&lt;/p&gt;

&lt;p&gt;Test with the &lt;code&gt;Tab&lt;/code&gt;, &lt;code&gt;Shift + Tab&lt;/code&gt;, &lt;code&gt;Enter&lt;/code&gt;, &lt;code&gt;Space&lt;/code&gt;, and &lt;code&gt;Escape&lt;/code&gt; keys.&lt;/p&gt;

&lt;p&gt;Make sure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Menus can be opened and closed.&lt;/li&gt;
&lt;li&gt;Buttons show visible focus styles.&lt;/li&gt;
&lt;li&gt;Modal windows do not trap people incorrectly.&lt;/li&gt;
&lt;li&gt;Dropdowns can be operated without a mouse.&lt;/li&gt;
&lt;li&gt;Forms can be completed in a logical order.&lt;/li&gt;
&lt;li&gt;Skip links or clear navigation patterns help users reach content quickly.&lt;/li&gt;
&lt;li&gt;Focus does not disappear behind sticky headers, cookie banners, or chat widgets.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is where many custom designs fail. A beautiful menu that only works with a mouse is not finished.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Fix Forms Before Anything Else
&lt;/h3&gt;

&lt;p&gt;Forms are where accessibility problems become lost leads.&lt;/p&gt;

&lt;p&gt;Review every form field:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does it have a visible label?&lt;/li&gt;
&lt;li&gt;Is the required status clear?&lt;/li&gt;
&lt;li&gt;Is the error message specific?&lt;/li&gt;
&lt;li&gt;Can the error be understood by screen readers?&lt;/li&gt;
&lt;li&gt;Does the form preserve user input after an error?&lt;/li&gt;
&lt;li&gt;Can the form be completed on mobile?&lt;/li&gt;
&lt;li&gt;Does the confirmation message explain what happens next?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a small business website, the contact form is often the money path. A form that looks modern but fails accessibility, validation, or email delivery is a business problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Keep Mobile Layouts Stable and Simple
&lt;/h3&gt;

&lt;p&gt;Mobile accessibility is not only about screen size. It is about touch targets, readable text, page stability, keyboard behavior, and friction.&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Buttons are easy to tap.&lt;/li&gt;
&lt;li&gt;Text does not require zooming.&lt;/li&gt;
&lt;li&gt;The phone number is selectable and tappable.&lt;/li&gt;
&lt;li&gt;Menus do not cover the page.&lt;/li&gt;
&lt;li&gt;Forms do not jump when the keyboard opens.&lt;/li&gt;
&lt;li&gt;Review widgets, maps, chat tools, and popups do not block the primary call to action.&lt;/li&gt;
&lt;li&gt;Content remains readable when text size is increased.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mobile is often the first visit, especially for local service searches. If the mobile experience is difficult, the business may never get a second chance.&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%2Fimages.unsplash.com%2Fphoto-1634944902853-3e977c2de8b6%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1634944902853-3e977c2de8b6%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Hand using an adaptive keyboard device for computer input" width="1200" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Accessible websites support different input methods, including keyboards, assistive devices, touch screens, and screen readers.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Match Structured Data to Visible Content
&lt;/h3&gt;

&lt;p&gt;Structured data helps search systems understand the page, but it must match what users can actually see.&lt;/p&gt;

&lt;p&gt;Google says it uses structured data to understand content and gather information about people, organizations, products, and other entities on the web (Google Search Central, n.d.-b). For small businesses, useful structured data often includes Organization, LocalBusiness, Service, FAQPage where appropriate, BreadcrumbList, and BlogPosting.&lt;/p&gt;

&lt;p&gt;The accessibility connection is straightforward: do not hide critical facts in code only. If the page schema says the business serves Florida, the page should visibly say that. If the schema describes a service, the page should clearly explain that service. If an FAQ is marked up, the question and answer should be visible to readers.&lt;/p&gt;

&lt;p&gt;This supports GEO because AI systems need reliable entity signals. It supports SEO because search systems can better classify the page. It supports accessibility because people get the same information machines get.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Review Third-Party Widgets
&lt;/h3&gt;

&lt;p&gt;Many accessibility failures come from tools added after launch:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Chat widgets.&lt;/li&gt;
&lt;li&gt;Review embeds.&lt;/li&gt;
&lt;li&gt;Booking calendars.&lt;/li&gt;
&lt;li&gt;Social feeds.&lt;/li&gt;
&lt;li&gt;Ad scripts.&lt;/li&gt;
&lt;li&gt;Cookie banners.&lt;/li&gt;
&lt;li&gt;CRM forms.&lt;/li&gt;
&lt;li&gt;Payment widgets.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not assume a vendor widget is accessible because the vendor is large. Test it. If it blocks a form, traps focus, lacks labels, creates layout shifts, or makes the mobile page harder to use, it needs configuration or replacement.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Test With Real Tasks
&lt;/h3&gt;

&lt;p&gt;A scan can find missing alt text. It cannot tell you whether a customer can confidently hire you.&lt;/p&gt;

&lt;p&gt;Run task-based tests:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the main service.&lt;/li&gt;
&lt;li&gt;Compare two service options.&lt;/li&gt;
&lt;li&gt;Read a pricing or process explanation.&lt;/li&gt;
&lt;li&gt;Find the service area.&lt;/li&gt;
&lt;li&gt;Submit the contact form.&lt;/li&gt;
&lt;li&gt;Tap the phone number.&lt;/li&gt;
&lt;li&gt;Navigate the page with only a keyboard.&lt;/li&gt;
&lt;li&gt;Increase browser zoom to 200%.&lt;/li&gt;
&lt;li&gt;Turn on a screen reader and listen to the page structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If those tasks are difficult, fix the design before adding more features.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Accessibility Improves SEO, AEO, and GEO
&lt;/h2&gt;

&lt;p&gt;Accessibility is not a separate lane from search. It strengthens the same signals that help people and machines understand a website.&lt;/p&gt;

&lt;p&gt;Accessible pages tend to have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clear headings.&lt;/li&gt;
&lt;li&gt;Descriptive links.&lt;/li&gt;
&lt;li&gt;Useful image descriptions.&lt;/li&gt;
&lt;li&gt;Text that can be crawled and read aloud.&lt;/li&gt;
&lt;li&gt;Stable mobile layouts.&lt;/li&gt;
&lt;li&gt;Logical form labels.&lt;/li&gt;
&lt;li&gt;Accurate structured data.&lt;/li&gt;
&lt;li&gt;Fewer confusing interactions.&lt;/li&gt;
&lt;li&gt;More complete answers to customer questions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That combination helps traditional SEO because search engines can parse the page. It helps AEO because direct answers are easier to extract. It helps GEO because AI answer systems need clear source material before they can cite or summarize a business accurately.&lt;/p&gt;

&lt;p&gt;For a small business, the goal is not to sound technical. The goal is to be understandable everywhere a customer may encounter you: Google, AI search, a screen reader, a phone browser, a desktop browser, and a referral link.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Should a Small Business Fix First?
&lt;/h2&gt;

&lt;p&gt;Start with the pages that make money.&lt;/p&gt;

&lt;p&gt;Prioritize:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Homepage.&lt;/li&gt;
&lt;li&gt;Contact page.&lt;/li&gt;
&lt;li&gt;Primary service pages.&lt;/li&gt;
&lt;li&gt;Paid ad landing pages.&lt;/li&gt;
&lt;li&gt;Booking or quote forms.&lt;/li&gt;
&lt;li&gt;High-traffic blog posts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then fix the highest-friction items:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Missing or confusing headings.&lt;/li&gt;
&lt;li&gt;Low contrast text.&lt;/li&gt;
&lt;li&gt;Buttons and links without clear names.&lt;/li&gt;
&lt;li&gt;Forms without labels or useful errors.&lt;/li&gt;
&lt;li&gt;Menus that fail keyboard or mobile users.&lt;/li&gt;
&lt;li&gt;Images that explain important content but have no useful alt text.&lt;/li&gt;
&lt;li&gt;Popups that cover the call to action.&lt;/li&gt;
&lt;li&gt;Structured data that does not match visible content.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This order keeps the work practical. Accessibility does not need to become an endless audit before anything improves.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Website Accessibility for Small Businesses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is website accessibility?
&lt;/h3&gt;

&lt;p&gt;Website accessibility means people with disabilities can perceive, navigate, understand, and interact with your website. That includes people using screen readers, keyboards, captions, zoom, voice control, assistive devices, and different visual or cognitive supports.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does every small business website need to follow WCAG?
&lt;/h3&gt;

&lt;p&gt;Legal obligations depend on the business, jurisdiction, website function, and customer relationship. From a design and risk standpoint, WCAG 2.2 is the best practical framework for improving accessibility. Businesses should consult qualified legal counsel for legal advice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does accessibility help SEO?
&lt;/h3&gt;

&lt;p&gt;Yes, when it improves clarity and usability. Clear headings, descriptive links, alt text, readable content, mobile usability, and accurate structured data all help search systems understand pages better. Accessibility should be done for people first, with SEO as a secondary benefit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are accessibility overlay widgets enough?
&lt;/h3&gt;

&lt;p&gt;No. An overlay cannot fix poor structure, unclear content, unlabeled forms, weak contrast, broken keyboard navigation, or inaccessible third-party widgets by itself. Accessibility needs to be built into the page and tested in the customer journey.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can small businesses get tax help for accessibility work?
&lt;/h3&gt;

&lt;p&gt;Some eligible small businesses may be able to claim the Disabled Access Credit for qualified access expenditures. The IRS says eligible small businesses use Form 8826 to claim the credit and that the credit is part of the general business credit (Internal Revenue Service, n.d.). Talk with a tax professional before relying on any tax benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Accessible websites are better business websites. They are easier to read, easier to navigate, easier to cite, easier to trust, and easier to use when a customer is ready to act.&lt;/p&gt;

&lt;p&gt;In 2026, small businesses should treat accessibility as part of website maintenance, not as a one-time redesign feature. Start with the money pages, fix the customer journey, use WCAG 2.2 as the practical standard, watch WCAG 3.0 as it develops, and make sure the information in your page content, images, forms, and structured data tells the same story.&lt;/p&gt;

&lt;p&gt;Echo Effect helps small businesses build websites that work for people, search engines, and AI answer systems. If your site has never had an accessibility review, start with the homepage, service pages, and contact form. That is where the fastest improvements usually live.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Google Search Central. (n.d.-a). &lt;em&gt;Image SEO best practices&lt;/em&gt;. Google for Developers. Retrieved August 3, 2026, from &lt;a href="https://developers.google.com/search/docs/appearance/google-images" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/appearance/google-images&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (n.d.-b). &lt;em&gt;Intro to how structured data markup works&lt;/em&gt;. Google for Developers. Retrieved August 3, 2026, from &lt;a href="https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Internal Revenue Service. (n.d.). &lt;em&gt;About Form 8826, Disabled Access Credit&lt;/em&gt;. Retrieved August 3, 2026, from &lt;a href="https://www.irs.gov/forms-pubs/about-form-8826" rel="noopener noreferrer"&gt;https://www.irs.gov/forms-pubs/about-form-8826&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;U.S. Department of Justice. (2022, March 18). &lt;em&gt;Guidance on web accessibility and the ADA&lt;/em&gt;. ADA.gov. &lt;a href="https://www.ada.gov/resources/web-guidance/" rel="noopener noreferrer"&gt;https://www.ada.gov/resources/web-guidance/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;U.S. Department of Justice. (2024, March 8). &lt;em&gt;Fact sheet: New rule on the accessibility of web content and mobile apps provided by state and local governments&lt;/em&gt;. ADA.gov. &lt;a href="https://www.ada.gov/resources/2024-03-08-web-rule/" rel="noopener noreferrer"&gt;https://www.ada.gov/resources/2024-03-08-web-rule/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;W3C. (2023, October 5). &lt;em&gt;Web Content Accessibility Guidelines (WCAG) 2.2&lt;/em&gt;. &lt;a href="https://www.w3.org/TR/WCAG22/" rel="noopener noreferrer"&gt;https://www.w3.org/TR/WCAG22/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;W3C. (n.d.). &lt;em&gt;Informative images&lt;/em&gt;. Web Accessibility Initiative. Retrieved August 3, 2026, from &lt;a href="https://www.w3.org/WAI/tutorials/images/informative/" rel="noopener noreferrer"&gt;https://www.w3.org/WAI/tutorials/images/informative/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;W3C. (2026a, March 3). &lt;em&gt;For review: WCAG 3 Working Draft, March 2026&lt;/em&gt;. Web Accessibility Initiative. &lt;a href="https://www.w3.org/WAI/news/2026-03-03/wcag3/" rel="noopener noreferrer"&gt;https://www.w3.org/WAI/news/2026-03-03/wcag3/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;W3C. (2026b). &lt;em&gt;WCAG 3 introduction&lt;/em&gt;. Web Accessibility Initiative. Retrieved August 3, 2026, from &lt;a href="https://www.w3.org/WAI/standards-guidelines/wcag/wcag3-intro/" rel="noopener noreferrer"&gt;https://www.w3.org/WAI/standards-guidelines/wcag/wcag3-intro/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>a11y</category>
      <category>webdesign</category>
      <category>seo</category>
    </item>
    <item>
      <title>Passkeys Are Becoming Default: Small Business Checklist</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 18 Aug 2026 15:27:37 +0000</pubDate>
      <link>https://dev.to/rverwey/passkeys-are-becoming-default-small-business-checklist-4bl</link>
      <guid>https://dev.to/rverwey/passkeys-are-becoming-default-small-business-checklist-4bl</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.echoeffect.net/blog/passkeys-default-small-business-checklist-2026" rel="noopener noreferrer"&gt;echoeffect.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Passwords are not disappearing overnight, but the direction is clear: business sign-ins are moving toward passkeys and phishing-resistant authentication.&lt;/p&gt;

&lt;p&gt;The current event that should get every small business owner's attention is Microsoft's July 2026 Entra ID update. Microsoft says passkeys will become the default authentication experience in Entra ID beginning September 1, 2026. Microsoft-provided SMS and voice authentication delivery will then be retired on February 1, 2027 for public cloud tenants (Microsoft, 2026a, 2026b).&lt;/p&gt;

&lt;p&gt;That does not only matter to enterprise IT teams. It matters to small businesses using Microsoft 365, Google Workspace, customer portals, booking platforms, CRMs, ecommerce accounts, website admin panels, password managers, payment processors, social media tools, and ad accounts.&lt;/p&gt;

&lt;p&gt;The short answer: if your business still relies on passwords, SMS codes, shared admin logins, or vendor-owned accounts, 2026 is the year to clean that up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Passkeys use public-key cryptography and device verification instead of reusable passwords. For most small businesses, the practical plan is to protect high-value accounts first, keep recovery clear, train staff, and phase out SMS MFA where stronger options are available.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is a Passkey?
&lt;/h2&gt;

&lt;p&gt;A passkey is a passwordless sign-in method built on FIDO and WebAuthn standards. Instead of typing a password that can be stolen or reused, the user verifies themselves on a trusted device with a fingerprint, face scan, screen lock, PIN, hardware security key, or credential manager.&lt;/p&gt;

&lt;p&gt;The important part happens behind the scenes. The website stores a public key. The user's device or credential provider keeps the private key. During sign-in, the device proves possession of the private key without sending a password to the website. web.dev explains that this design reduces phishing risk and credential theft because the private key signs a challenge for the valid domain, and the server verifies the result with the stored public key (Kitamura, 2026).&lt;/p&gt;

&lt;p&gt;In plain English: a passkey is harder to steal than a password because there is no shared password to type into a fake login page.&lt;/p&gt;

&lt;p&gt;Passkeys can be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Synced passkeys:&lt;/strong&gt; Stored in a credential manager such as iCloud Keychain, Google Password Manager, or another supported provider, then synced across the user's devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Device-bound passkeys:&lt;/strong&gt; Stored on a specific device, such as a phone, computer, Microsoft Authenticator passkey, Windows Hello credential, or FIDO2 hardware security key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both categories can be useful. The right choice depends on the account, user, device ownership, recovery needs, and risk level.&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%2Fimages.unsplash.com%2Fphoto-1633265486064-086b219458ec%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1633265486064-086b219458ec%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Combination lock and smart cards on a computer keyboard representing older authentication methods" width="1200" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Small businesses should not wait for a forced migration before replacing weak sign-in methods on critical accounts.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters Right Now
&lt;/h2&gt;

&lt;p&gt;Microsoft's announcement gives the market a clear signal. SMS and voice codes helped many organizations adopt MFA, but Microsoft now describes them as phishable methods that provide weaker protection than passkeys. Microsoft also says users enabled for SMS or voice in Entra ID will be auto-enabled and nudged to register passkeys beginning September 1, 2026, and users who still depend on Microsoft-provided SMS or voice after February 1, 2027 will face a blocking registration prompt before continuing to sign in (Microsoft, 2026a).&lt;/p&gt;

&lt;p&gt;This is not an isolated vendor preference. The broader identity market has been moving this way for years.&lt;/p&gt;

&lt;p&gt;The FIDO Alliance reported in its 2026 global passkey research that passkeys have reached 5 billion active credentials, 90% consumer awareness, and 75% consumer enablement on at least some accounts. It also reported that 68% of surveyed organizations were deploying, piloting, or rolling out passkeys for employee authentication (FIDO Alliance, 2026).&lt;/p&gt;

&lt;p&gt;The business case is not only security. FIDO's 2025 Passkey Index reported a 93% success rate for passkey logins compared with 63% for other methods among participating platforms. The same report said passkey sign-ins averaged 8.5 seconds compared with 31.2 seconds for traditional MFA methods, a 73% decrease in login time (FIDO Alliance, 2025).&lt;/p&gt;

&lt;p&gt;For a small business, that means authentication is both a security issue and a workflow issue. Every failed login, reset ticket, locked-out employee, vendor handoff, and forgotten password wastes time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Small Business Risk: Not Just "Hackers"
&lt;/h2&gt;

&lt;p&gt;Most small businesses do not lose accounts because a genius attacker breaks cryptography. They lose accounts because of ordinary operational gaps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One shared admin account controls the website.&lt;/li&gt;
&lt;li&gt;A former vendor still has access.&lt;/li&gt;
&lt;li&gt;SMS MFA is tied to a phone number nobody owns anymore.&lt;/li&gt;
&lt;li&gt;Password reset email goes to a stale inbox.&lt;/li&gt;
&lt;li&gt;A staff member reuses a password from a personal account.&lt;/li&gt;
&lt;li&gt;A fake Microsoft 365 login page captures credentials.&lt;/li&gt;
&lt;li&gt;A social media account has no recovery owner.&lt;/li&gt;
&lt;li&gt;A password manager vault has no business continuity plan.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Passkeys do not fix every one of those problems by themselves. They do reduce the risk that a reused or phished password becomes the easy way in. They also force the business to answer questions that should already be documented: who owns each account, which devices are trusted, how access is recovered, and who can approve changes.&lt;/p&gt;

&lt;p&gt;That is why passkey planning belongs in website maintenance, SEO, AEO, and GEO work. If attackers take over your website admin, Google Business Profile, social accounts, or email domain, the damage is not limited to IT. It can break lead flow, damage local search trust, interrupt ad campaigns, and pollute the public signals that search engines and AI answer systems use to understand your business.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Protect First
&lt;/h2&gt;

&lt;p&gt;Do not start with every account in the company. Start with the accounts that can change money, identity, website content, customer data, or public trust.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Priority&lt;/th&gt;
&lt;th&gt;Account type&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Microsoft 365 or Google Workspace admins&lt;/td&gt;
&lt;td&gt;Controls email, identity, reset paths, files, and often domain trust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Domain registrar and DNS&lt;/td&gt;
&lt;td&gt;Controls where the website, email, and verification records point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Website hosting and CMS admin&lt;/td&gt;
&lt;td&gt;Controls public pages, forms, plugins, redirects, and scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Payment, banking, payroll, and invoicing&lt;/td&gt;
&lt;td&gt;Direct financial risk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Password manager administrator&lt;/td&gt;
&lt;td&gt;Controls access to many other systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Google Business Profile and ad accounts&lt;/td&gt;
&lt;td&gt;Controls local visibility, paid traffic, and brand trust&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Facebook, Instagram, LinkedIn, and YouTube&lt;/td&gt;
&lt;td&gt;Controls public reputation and customer communication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;CRM, booking, and form tools&lt;/td&gt;
&lt;td&gt;Controls customer records and lead flow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a small business only has time for one security improvement this month, protect the accounts at the top of that list.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Passkey Rollout Checklist
&lt;/h2&gt;

&lt;p&gt;This checklist is written for small business owners, office managers, agencies, and web teams. You do not need to implement everything in one day. You do need a written migration path.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Inventory Accounts and Owners
&lt;/h3&gt;

&lt;p&gt;Create a simple account inventory. Include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Account name.&lt;/li&gt;
&lt;li&gt;Business purpose.&lt;/li&gt;
&lt;li&gt;Primary owner.&lt;/li&gt;
&lt;li&gt;Backup owner.&lt;/li&gt;
&lt;li&gt;Login URL.&lt;/li&gt;
&lt;li&gt;MFA method.&lt;/li&gt;
&lt;li&gt;Recovery email or phone.&lt;/li&gt;
&lt;li&gt;Vendor access.&lt;/li&gt;
&lt;li&gt;Last access review date.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This does not need to be fancy. A secure password manager, spreadsheet, or internal IT document can work if access is controlled.&lt;/p&gt;

&lt;p&gt;The goal is to eliminate mystery. If nobody knows who owns the domain registrar, the business has a security and continuity problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Move Admins First
&lt;/h3&gt;

&lt;p&gt;Roll passkeys or phishing-resistant MFA to administrators before general staff. Admin accounts can reset users, change DNS, install plugins, delete files, alter billing, and grant vendor access.&lt;/p&gt;

&lt;p&gt;For Microsoft Entra users, Microsoft recommends identifying users enabled for SMS or voice, enabling passkeys, using registration campaigns, and communicating the change before the rollout hits users (Microsoft, 2026a, 2026b).&lt;/p&gt;

&lt;p&gt;For other systems, the same pattern applies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify who still uses password-only sign-in or SMS MFA.&lt;/li&gt;
&lt;li&gt;Confirm the platform supports passkeys, FIDO2 security keys, or another phishing-resistant method.&lt;/li&gt;
&lt;li&gt;Pilot with owners and admins.&lt;/li&gt;
&lt;li&gt;Document recovery.&lt;/li&gt;
&lt;li&gt;Roll out to the rest of the team.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Keep Recovery Strong
&lt;/h3&gt;

&lt;p&gt;Weak recovery can undo strong authentication. If support can remove MFA after someone answers easy questions, attackers will target the recovery process instead of the login screen.&lt;/p&gt;

&lt;p&gt;web.dev recommends notifying users after passkey registration so unauthorized passkey creation can be detected (Kitamura, 2026). For businesses, that principle should expand into a broader recovery plan.&lt;/p&gt;

&lt;p&gt;Document:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Who can approve account recovery.&lt;/li&gt;
&lt;li&gt;How identity is verified before resetting access.&lt;/li&gt;
&lt;li&gt;Which email receives security alerts.&lt;/li&gt;
&lt;li&gt;Where backup codes are stored.&lt;/li&gt;
&lt;li&gt;Which devices can create or use passkeys.&lt;/li&gt;
&lt;li&gt;What happens when a phone, laptop, or security key is lost.&lt;/li&gt;
&lt;li&gt;How vendor access is removed at the end of a project.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not rely on one phone number, one employee, or one vendor relationship as the only recovery path.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Separate Shared Work From Shared Logins
&lt;/h3&gt;

&lt;p&gt;Many small businesses still share one login because "everyone needs access." That is exactly the habit passkeys should help replace.&lt;/p&gt;

&lt;p&gt;Use individual accounts with role-based access whenever possible. A social media scheduler, CMS, ad account, Google Business Profile, CRM, or password manager should allow named users or roles. Shared logins make it hard to revoke access, audit activity, and recover safely.&lt;/p&gt;

&lt;p&gt;If a platform only supports one login, store it in a business password manager, protect the vault with strong MFA, and document who can use it. Then plan to move away from that platform if account sharing creates material risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Choose Passkey Types Intentionally
&lt;/h3&gt;

&lt;p&gt;Synced passkeys are convenient because users can access accounts across devices through their credential provider. Device-bound passkeys can be stricter because they stay tied to a specific authenticator or security key.&lt;/p&gt;

&lt;p&gt;NIST's SP 800-63 Revision 4, finalized in July 2025, explicitly integrates syncable authenticators such as synced passkeys into its updated digital identity guidance (NIST, 2025). That is a signal that synced passkeys are part of mainstream identity planning, not a niche convenience feature.&lt;/p&gt;

&lt;p&gt;For small businesses:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use synced passkeys for lower-risk employee workflows where convenience and recovery matter.&lt;/li&gt;
&lt;li&gt;Consider device-bound passkeys or hardware security keys for owners, admins, finance, and critical systems.&lt;/li&gt;
&lt;li&gt;Avoid letting unmanaged personal devices become the only path into business-critical accounts.&lt;/li&gt;
&lt;li&gt;Keep at least two recovery-capable owners for critical systems.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  6. Train People Before Prompts Appear
&lt;/h3&gt;

&lt;p&gt;Passkey adoption fails when users see a security prompt they do not understand. Explain the change before rollout.&lt;/p&gt;

&lt;p&gt;Your internal note should answer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is changing?&lt;/li&gt;
&lt;li&gt;Why are passwords and SMS codes being reduced?&lt;/li&gt;
&lt;li&gt;Which accounts are affected first?&lt;/li&gt;
&lt;li&gt;What device should the person use?&lt;/li&gt;
&lt;li&gt;What should they do if they lose a device?&lt;/li&gt;
&lt;li&gt;Who should they contact before approving a strange prompt?&lt;/li&gt;
&lt;li&gt;What does a real registration flow look like?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Keep the language simple. A staff member does not need a cryptography lesson. They need to know which prompts are expected and which prompts should be reported.&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%2Fimages.unsplash.com%2Fphoto-1585079374502-415f8516dcc3%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1585079374502-415f8516dcc3%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Fingerprint scanner representing biometric verification for account access" width="1200" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Passkeys reduce phishing risk, but the rollout still needs clear ownership, secure recovery, and user training.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Website and SEO Implications
&lt;/h2&gt;

&lt;p&gt;Passkeys may sound like an internal IT topic, but they have direct website consequences.&lt;/p&gt;

&lt;p&gt;Your website and marketing accounts are usually connected to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Domain DNS.&lt;/li&gt;
&lt;li&gt;Website hosting.&lt;/li&gt;
&lt;li&gt;CMS admin.&lt;/li&gt;
&lt;li&gt;Email delivery.&lt;/li&gt;
&lt;li&gt;Analytics.&lt;/li&gt;
&lt;li&gt;Google Search Console.&lt;/li&gt;
&lt;li&gt;Google Business Profile.&lt;/li&gt;
&lt;li&gt;Ad platforms.&lt;/li&gt;
&lt;li&gt;Social media profiles.&lt;/li&gt;
&lt;li&gt;Forms, booking tools, and CRM systems.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any of those accounts are compromised, your SEO and AEO work can be damaged quickly. Attackers can add spam pages, change redirects, break forms, swap tracking scripts, abuse email, alter business details, publish fake posts, or block crawlers.&lt;/p&gt;

&lt;p&gt;Google's 2026 guidance for generative AI features says AI search visibility still depends on foundational SEO: helpful content, crawlability, technical structure, page experience, and high-quality supporting images or video (Google Search Central, 2026). A compromised or unstable site weakens those signals.&lt;/p&gt;

&lt;p&gt;The AEO and GEO lesson is simple: trustworthy content requires trustworthy operations. A business cannot expect search engines and AI answer systems to cite accurate information if account security allows the public facts about the business to be changed by the wrong person.&lt;/p&gt;

&lt;p&gt;For related visibility work, read Echo Effect's guides to &lt;a href="https://dev.to/blog/answer-engine-optimization-2026"&gt;answer engine optimization&lt;/a&gt;, &lt;a href="https://dev.to/blog/ai-crawler-access-small-business-websites-2026"&gt;AI crawler access&lt;/a&gt;, and &lt;a href="https://dev.to/blog/small-business-website-vulnerability-checklist-2026"&gt;website vulnerability management&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Passkeys Are Not Magic
&lt;/h2&gt;

&lt;p&gt;Passkeys are a major improvement, but they are not a complete security program.&lt;/p&gt;

&lt;p&gt;They do not replace:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Device updates.&lt;/li&gt;
&lt;li&gt;Malware protection.&lt;/li&gt;
&lt;li&gt;Vendor offboarding.&lt;/li&gt;
&lt;li&gt;Backup planning.&lt;/li&gt;
&lt;li&gt;Least-privilege access.&lt;/li&gt;
&lt;li&gt;Secure recovery.&lt;/li&gt;
&lt;li&gt;Phishing awareness.&lt;/li&gt;
&lt;li&gt;Website patching.&lt;/li&gt;
&lt;li&gt;Monitoring for suspicious changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They also introduce practical questions. Which devices are allowed? What happens when an employee leaves? Can the business recover if the owner's phone is lost? Are passkeys stored in a personal credential manager or a managed business system? Do vendors need their own accounts?&lt;/p&gt;

&lt;p&gt;Those questions are solvable, but they should be answered before a forced platform change creates urgency.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Passkeys for Small Businesses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Should every small business use passkeys?
&lt;/h3&gt;

&lt;p&gt;Most small businesses should use passkeys where important platforms support them, especially for email, domain, hosting, website, finance, and admin accounts. If passkeys are not available, use the strongest MFA option available and plan to upgrade.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are passkeys better than SMS codes?
&lt;/h3&gt;

&lt;p&gt;Yes for most business sign-in scenarios. SMS codes can be phished, intercepted, socially engineered, or affected by SIM-swap attacks. Passkeys are designed to be phishing-resistant because they use cryptographic keys tied to the legitimate domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a passkey be stolen?
&lt;/h3&gt;

&lt;p&gt;A passkey is much harder to steal than a password, but no system is perfect. Attackers may still target devices, recovery processes, malware, support desks, or compromised credential providers. That is why passkeys should be paired with device security and strong recovery rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if an employee loses their phone?
&lt;/h3&gt;

&lt;p&gt;The business needs a documented recovery process before rollout. Keep at least two account owners for critical systems, store recovery codes securely, and make sure recovery does not depend on one person, one phone number, or one vendor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do passkeys help SEO?
&lt;/h3&gt;

&lt;p&gt;Indirectly, yes. Passkeys do not make a page rank higher by themselves. They help protect the accounts that control website content, DNS, analytics, business listings, ads, and crawl visibility. Stronger account security protects the trust signals that SEO, AEO, and GEO depend on.&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I do this week?
&lt;/h3&gt;

&lt;p&gt;Start with your highest-risk accounts. Review Microsoft 365 or Google Workspace admins, domain registrar access, hosting, CMS admin accounts, password manager ownership, Google Business Profile, ad accounts, and social media profiles. Turn on passkeys or phishing-resistant MFA where available.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Passkeys are moving from optional upgrade to default expectation. Microsoft's 2026 Entra timeline makes that obvious, and broader FIDO adoption data shows the market is ready.&lt;/p&gt;

&lt;p&gt;Small businesses should not treat this as an enterprise-only issue. Your website, email, domain, ads, social profiles, CRM, booking tools, and payment systems all depend on identity security.&lt;/p&gt;

&lt;p&gt;Start with ownership. Protect the accounts that can change public trust or move money. Replace SMS MFA where stronger options are available. Train users before prompts appear. Keep recovery documented. Review access monthly.&lt;/p&gt;

&lt;p&gt;Good authentication is not separate from digital marketing anymore. It protects the systems that keep your website live, your lead flow working, your local business details accurate, and your search visibility trustworthy.&lt;/p&gt;

&lt;p&gt;Echo Effect helps small businesses build and maintain websites with practical security, SEO, AEO, and GEO in mind. If your business does not know who owns every critical login, start there before the next forced platform change starts the clock.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Cybersecurity and Infrastructure Security Agency. (n.d.). &lt;em&gt;Require multifactor authentication&lt;/em&gt;. Retrieved July 27, 2026, from &lt;a href="https://www.cisa.gov/audiences/small-and-medium-businesses/secure-your-business/require-multifactor-authentication" rel="noopener noreferrer"&gt;https://www.cisa.gov/audiences/small-and-medium-businesses/secure-your-business/require-multifactor-authentication&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FIDO Alliance. (2025, October). &lt;em&gt;Passkey Index&lt;/em&gt;. &lt;a href="https://fidoalliance.org/wp-content/uploads/2025/10/FIDO-Passkey-Index-October-2025.pdf" rel="noopener noreferrer"&gt;https://fidoalliance.org/wp-content/uploads/2025/10/FIDO-Passkey-Index-October-2025.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FIDO Alliance. (2026, May 7). &lt;em&gt;The state of passkeys 2026: Global consumer and workforce report&lt;/em&gt;. &lt;a href="https://fidoalliance.org/the-state-of-passkeys-2026-global-consumer-and-workforce-report/" rel="noopener noreferrer"&gt;https://fidoalliance.org/the-state-of-passkeys-2026-global-consumer-and-workforce-report/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (2026, July 10). &lt;em&gt;Optimizing your website for generative AI features on Google Search&lt;/em&gt;. Google for Developers. &lt;a href="https://developers.google.com/search/docs/fundamentals/ai-optimization-guide" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/fundamentals/ai-optimization-guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kitamura, E. (2026, April 9). &lt;em&gt;Create a passkey for passwordless logins&lt;/em&gt;. web.dev. &lt;a href="https://web.dev/articles/passkey-registration" rel="noopener noreferrer"&gt;https://web.dev/articles/passkey-registration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Microsoft. (2026a, July 21). &lt;em&gt;Passkeys by default and retirement of Microsoft-provided SMS and voice authentication&lt;/em&gt;. Microsoft Learn. &lt;a href="https://learn.microsoft.com/en-us/entra/identity/authentication/concept-sms-voice-retirement" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/entra/identity/authentication/concept-sms-voice-retirement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Microsoft. (2026b, July 13). &lt;em&gt;Microsoft Entra ID security updates: Passkeys are the default authentication method in Entra ID&lt;/em&gt;. Microsoft Security Blog. &lt;a href="https://www.microsoft.com/en-us/security/blog/2026/07/13/microsoft-entra-id-security-updates-passkeys-are-the-default-authentication-method-in-entra-id/" rel="noopener noreferrer"&gt;https://www.microsoft.com/en-us/security/blog/2026/07/13/microsoft-entra-id-security-updates-passkeys-are-the-default-authentication-method-in-entra-id/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;National Institute of Standards and Technology. (2025, July). &lt;em&gt;SP 800-63 Digital Identity Guidelines&lt;/em&gt;. &lt;a href="https://pages.nist.gov/800-63-4/" rel="noopener noreferrer"&gt;https://pages.nist.gov/800-63-4/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>javascript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Website Vulnerability Checklist for Small Businesses in 2026</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 18 Aug 2026 15:27:33 +0000</pubDate>
      <link>https://dev.to/rverwey/website-vulnerability-checklist-for-small-businesses-in-2026-47lo</link>
      <guid>https://dev.to/rverwey/website-vulnerability-checklist-for-small-businesses-in-2026-47lo</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.echoeffect.net/blog/small-business-website-vulnerability-checklist-2026" rel="noopener noreferrer"&gt;echoeffect.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Website security used to feel like an enterprise problem. In 2026, it is a small business website problem too.&lt;/p&gt;

&lt;p&gt;Verizon's 2026 Data Breach Investigations Report found that 31% of breaches now start with software vulnerabilities, making vulnerability exploitation the top breach entry point in the report's public summary (Verizon, 2026a, 2026b). That is not just a warning for banks, hospitals, or SaaS companies. It matters for service businesses, local retailers, restaurants, contractors, medical offices, law firms, and consultants whose websites collect leads, connect to email, load third-party scripts, and depend on plugins, packages, themes, forms, analytics, booking tools, or hosting panels.&lt;/p&gt;

&lt;p&gt;The short answer: a small business website needs a maintenance process, not a one-time launch. If no one is checking updates, reviewing dependencies, testing forms, watching logs, and removing unused software, the site gets riskier every month.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Treat website vulnerability management like bookkeeping. Assign an owner, review it on a schedule, document what changed, and fix high-risk issues before they become emergencies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Vulnerability Exploitation Is a Business Issue
&lt;/h2&gt;

&lt;p&gt;A vulnerable website does not need to hold credit card data to hurt the business. Attackers can abuse ordinary marketing sites in several ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inject spam pages that damage search visibility.&lt;/li&gt;
&lt;li&gt;Steal form submissions or customer contact details.&lt;/li&gt;
&lt;li&gt;Redirect visitors to scams.&lt;/li&gt;
&lt;li&gt;Use the site to host malware.&lt;/li&gt;
&lt;li&gt;Abuse server resources and increase hosting costs.&lt;/li&gt;
&lt;li&gt;Break the lead path by taking forms, pages, or booking tools offline.&lt;/li&gt;
&lt;li&gt;Expose admin accounts, API keys, or SMTP credentials.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last point is often missed. Many small business websites connect to services that are more sensitive than the public page itself. A contact form may connect to Microsoft 365 SMTP. A booking widget may connect to a calendar. An analytics script may connect to ad accounts. A plugin may store an API key. A neglected website can become a doorway into tools the business depends on.&lt;/p&gt;

&lt;p&gt;This is why security belongs in the same conversation as SEO, AEO, and GEO. Search engines and AI answer systems need stable, trustworthy, crawlable pages. If a website gets defaced, injected with spam, blocked by browsers, or knocked offline, visibility suffers along with customer trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed in 2026
&lt;/h2&gt;

&lt;p&gt;The most important shift is speed. Verizon reported that vulnerability exploitation rose to 31% of breaches and surpassed stolen credentials as the leading entry point (Verizon, 2026a). Verizon's public news summary also says attackers are using AI to accelerate exploitation, shrinking the response window from months to hours (Verizon, 2026b).&lt;/p&gt;

&lt;p&gt;That does not mean AI is the root cause of every attack. It means old maintenance habits are no longer good enough. Waiting a quarter to apply a critical patch is too slow when attackers can scan the internet, find known vulnerable software, and automate exploitation quickly.&lt;/p&gt;

&lt;p&gt;For small businesses, the practical lesson is simple: do not wait until the website visibly breaks. Most serious website security work is boring on purpose. It is version checks, patch notes, backups, access reviews, log checks, and test deployments.&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%2Fimages.unsplash.com%2Fphoto-1642783327549-db8f4487dd68%3Fauto%3Dformat%26fit%3Dcrop%26fm%3Djpg%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D%26ixlib%3Drb-4.1.0%26q%3D60%26w%3D3000" 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%2Fimages.unsplash.com%2Fphoto-1642783327549-db8f4487dd68%3Fauto%3Dformat%26fit%3Dcrop%26fm%3Djpg%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D%26ixlib%3Drb-4.1.0%26q%3D60%26w%3D3000" alt="Laptop screen showing a security threat alert" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Small business website security should focus on fast detection, fast patching, and clean recovery before a warning becomes visible to customers.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Five Risk Areas to Review First
&lt;/h2&gt;

&lt;p&gt;Small businesses do not need a 60-page security program to start. They need to focus on the website surfaces that most often create practical risk.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Risk area&lt;/th&gt;
&lt;th&gt;What to check first&lt;/th&gt;
&lt;th&gt;Business reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Access control&lt;/td&gt;
&lt;td&gt;Admin users, roles, MFA, staging access&lt;/td&gt;
&lt;td&gt;Prevent unauthorized site changes and private content exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security misconfiguration&lt;/td&gt;
&lt;td&gt;Debug mode, public backups, headers, runtime versions&lt;/td&gt;
&lt;td&gt;Reduce quiet mistakes that make a normal site easy to abuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Software supply chain&lt;/td&gt;
&lt;td&gt;Plugins, packages, themes, lockfiles, abandoned tools&lt;/td&gt;
&lt;td&gt;Limit risk from third-party code your business depends on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Injection&lt;/td&gt;
&lt;td&gt;Forms, search, booking tools, custom integrations&lt;/td&gt;
&lt;td&gt;Protect databases, lead data, and connected business systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-site scripting&lt;/td&gt;
&lt;td&gt;Displayed user input, widgets, unsafe scripts&lt;/td&gt;
&lt;td&gt;Protect visitors from attacker-controlled scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1. Access Control
&lt;/h3&gt;

&lt;p&gt;OWASP lists Broken Access Control as the number one risk in the OWASP Top 10:2025, and its introduction says this category remains the most serious application security risk (OWASP Foundation, 2025a, 2025b).&lt;/p&gt;

&lt;p&gt;For a small business website, access control usually means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Admin logins.&lt;/li&gt;
&lt;li&gt;CMS roles.&lt;/li&gt;
&lt;li&gt;Customer portal permissions.&lt;/li&gt;
&lt;li&gt;Staging site protection.&lt;/li&gt;
&lt;li&gt;File uploads.&lt;/li&gt;
&lt;li&gt;Private pages.&lt;/li&gt;
&lt;li&gt;API routes.&lt;/li&gt;
&lt;li&gt;Form submission endpoints.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The question is not only "Can someone log in?" The better question is "Can someone access something they should not be able to access?"&lt;/p&gt;

&lt;p&gt;Use strong passwords, require multifactor authentication where available, remove former vendors and employees, avoid shared admin accounts, protect staging sites, and limit each user to the access they actually need.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Security Misconfiguration
&lt;/h3&gt;

&lt;p&gt;OWASP moved Security Misconfiguration to number two in the 2025 list, noting that modern software increasingly depends on configuration choices (OWASP Foundation, 2025b). That matters because small business sites often combine hosting settings, DNS records, CDN rules, form settings, cache settings, environment variables, redirects, robots rules, and third-party scripts.&lt;/p&gt;

&lt;p&gt;Common misconfigurations include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Public staging sites indexed by Google.&lt;/li&gt;
&lt;li&gt;Debug mode left on in production.&lt;/li&gt;
&lt;li&gt;Overly broad file permissions.&lt;/li&gt;
&lt;li&gt;Missing security headers.&lt;/li&gt;
&lt;li&gt;Old PHP or Node versions.&lt;/li&gt;
&lt;li&gt;Exposed environment files.&lt;/li&gt;
&lt;li&gt;Public admin paths without rate limiting.&lt;/li&gt;
&lt;li&gt;Backups stored inside the public web root.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Misconfiguration is dangerous because the site can look normal while the risk is sitting in plain sight.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Software Supply Chain Failures
&lt;/h3&gt;

&lt;p&gt;OWASP added Software Supply Chain Failures as a top-three risk in 2025 (OWASP Foundation, 2025c). This category is especially relevant for modern websites because few sites are built from one piece of software. A simple business website may depend on dozens or hundreds of packages, plugins, themes, build tools, hosting adapters, and third-party scripts.&lt;/p&gt;

&lt;p&gt;The business owner does not need to audit every line of code personally. They do need someone to own these questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What platform, framework, plugins, packages, and themes does the site use?&lt;/li&gt;
&lt;li&gt;Which dependencies are outdated or abandoned?&lt;/li&gt;
&lt;li&gt;Are updates tested before production?&lt;/li&gt;
&lt;li&gt;Can a bad update be rolled back quickly?&lt;/li&gt;
&lt;li&gt;Are lockfiles, plugin inventories, and hosting versions documented?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If nobody can answer those questions, the website is harder to defend and harder to recover.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Injection
&lt;/h3&gt;

&lt;p&gt;CISA and the FBI warned in March 2024 that SQL injection remains a persistent class of defect despite decades of known mitigations. Their Secure by Design alert explains that SQL injection happens when user-supplied input is inserted into a SQL command, and recommends parameterized queries with prepared statements as the standard defense (CISA &amp;amp; FBI, 2024a).&lt;/p&gt;

&lt;p&gt;Small businesses usually encounter injection risk through forms, search boxes, booking tools, old plugins, custom dashboards, and poorly built integrations.&lt;/p&gt;

&lt;p&gt;The fix is not "sanitize harder" as a vague slogan. The fix is to use secure framework defaults, parameterized database access, server-side validation, and code review on every feature that accepts user input.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Cross-Site Scripting
&lt;/h3&gt;

&lt;p&gt;CISA and the FBI also warned that cross-site scripting remains preventable and should not be present in software products. Their September 2024 alert says XSS can allow malicious scripts to be injected into web applications, and recommends input validation, output encoding, code reviews, threat modeling, and adversarial testing (CISA &amp;amp; FBI, 2024b).&lt;/p&gt;

&lt;p&gt;For small businesses, XSS risk often appears in places that accept or display content:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Contact forms.&lt;/li&gt;
&lt;li&gt;Review widgets.&lt;/li&gt;
&lt;li&gt;Blog comments.&lt;/li&gt;
&lt;li&gt;Search results.&lt;/li&gt;
&lt;li&gt;Admin dashboards.&lt;/li&gt;
&lt;li&gt;Customer messages.&lt;/li&gt;
&lt;li&gt;User-uploaded content.&lt;/li&gt;
&lt;li&gt;Embedded third-party scripts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Modern frameworks help, but they do not eliminate every edge case. Be careful with custom HTML, unsafe script injection, poorly reviewed plugins, and any feature that displays untrusted text.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Website Vulnerability Checklist
&lt;/h2&gt;

&lt;p&gt;Use this checklist monthly, and immediately after a high-severity advisory affects your website stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confirm Ownership
&lt;/h3&gt;

&lt;p&gt;Assign one person or vendor to own website maintenance. "The hosting company probably handles it" is not a plan. Hosting providers may patch infrastructure, but they usually do not update your custom code, plugins, content system, DNS rules, analytics scripts, or business workflows.&lt;/p&gt;

&lt;p&gt;Your owner should document:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Website platform and version.&lt;/li&gt;
&lt;li&gt;Hosting provider.&lt;/li&gt;
&lt;li&gt;DNS provider.&lt;/li&gt;
&lt;li&gt;CMS admin users.&lt;/li&gt;
&lt;li&gt;Framework and package manager.&lt;/li&gt;
&lt;li&gt;Plugins, apps, themes, and integrations.&lt;/li&gt;
&lt;li&gt;Contact form delivery path.&lt;/li&gt;
&lt;li&gt;Backup location and restore process.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Patch the Stack
&lt;/h3&gt;

&lt;p&gt;Review the full stack, not only the visible website.&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CMS core.&lt;/li&gt;
&lt;li&gt;Plugins and themes.&lt;/li&gt;
&lt;li&gt;JavaScript packages.&lt;/li&gt;
&lt;li&gt;Server runtime, such as Node or PHP.&lt;/li&gt;
&lt;li&gt;Framework versions.&lt;/li&gt;
&lt;li&gt;Hosting build images.&lt;/li&gt;
&lt;li&gt;Form libraries.&lt;/li&gt;
&lt;li&gt;Email dependencies.&lt;/li&gt;
&lt;li&gt;Analytics and marketing scripts.&lt;/li&gt;
&lt;li&gt;CDN, cache, and WAF settings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NIST's Secure Software Development Framework recommends secure development practices that reduce vulnerabilities in released software, mitigate the impact of issues that still slip through, and address root causes to prevent recurrence (Souppaya et al., 2022). In plain terms, patching should be part of the way the website is managed, not a panic task after something goes wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove What You Do Not Use
&lt;/h3&gt;

&lt;p&gt;Unused software is easy to ignore and hard to defend. Remove inactive plugins, old themes, unused packages, abandoned scripts, test pages, stale admin accounts, and old integrations.&lt;/p&gt;

&lt;p&gt;Every unused dependency is another thing that can become vulnerable without providing business value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protect Admin Access
&lt;/h3&gt;

&lt;p&gt;Lock down the accounts that can change the site.&lt;/p&gt;

&lt;p&gt;At minimum:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Require unique passwords.&lt;/li&gt;
&lt;li&gt;Enable multifactor authentication where possible.&lt;/li&gt;
&lt;li&gt;Remove former employees and vendors.&lt;/li&gt;
&lt;li&gt;Avoid shared administrator accounts.&lt;/li&gt;
&lt;li&gt;Limit admin roles.&lt;/li&gt;
&lt;li&gt;Review password reset emails.&lt;/li&gt;
&lt;li&gt;Rate limit login attempts where the platform supports it.&lt;/li&gt;
&lt;li&gt;Keep recovery codes in a secure place.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Access control is usually cheaper to fix before an incident than after an account is abused.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Lead Path After Updates
&lt;/h3&gt;

&lt;p&gt;Security updates can break important workflows if they are rushed. After every material update, test the actual customer path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Homepage loads.&lt;/li&gt;
&lt;li&gt;Service pages load.&lt;/li&gt;
&lt;li&gt;Contact form submits.&lt;/li&gt;
&lt;li&gt;Email notification arrives.&lt;/li&gt;
&lt;li&gt;Calendar or booking link works.&lt;/li&gt;
&lt;li&gt;Phone links and CTA buttons work.&lt;/li&gt;
&lt;li&gt;Blog posts render.&lt;/li&gt;
&lt;li&gt;Images load.&lt;/li&gt;
&lt;li&gt;Sitemap and robots.txt still respond.&lt;/li&gt;
&lt;li&gt;Analytics and conversion tracking still fire.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Good maintenance protects security and revenue at the same time.&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%2Fimages.unsplash.com%2Fphoto-1762340915700-356b34475448%3Fauto%3Dformat%26fit%3Dcrop%26fm%3Djpg%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D%26ixlib%3Drb-4.1.0%26q%3D60%26w%3D3000" 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%2Fimages.unsplash.com%2Fphoto-1762340915700-356b34475448%3Fauto%3Dformat%26fit%3Dcrop%26fm%3Djpg%26ixid%3DM3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%253D%253D%26ixlib%3Drb-4.1.0%26q%3D60%26w%3D3000" alt="Security software quick scan screen" width="3000" height="1871"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A useful maintenance plan checks vulnerable areas regularly, documents what changed, and confirms the customer journey still works.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Ask Your Web Developer or Agency
&lt;/h2&gt;

&lt;p&gt;If someone else manages your website, send these questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What platform, framework, CMS, plugins, and runtime versions are live right now?&lt;/li&gt;
&lt;li&gt;Which parts of the site accept user input?&lt;/li&gt;
&lt;li&gt;Are any plugins, packages, or themes abandoned?&lt;/li&gt;
&lt;li&gt;How quickly do we patch critical vulnerabilities?&lt;/li&gt;
&lt;li&gt;Do we test updates before production?&lt;/li&gt;
&lt;li&gt;What backup can we restore from today?&lt;/li&gt;
&lt;li&gt;How often are admin users reviewed?&lt;/li&gt;
&lt;li&gt;Is multifactor authentication enabled for admin access?&lt;/li&gt;
&lt;li&gt;Are forms protected against spam and abuse?&lt;/li&gt;
&lt;li&gt;Do we monitor uptime, form failures, and crawl errors?&lt;/li&gt;
&lt;li&gt;Who gets notified when a security advisory affects our stack?&lt;/li&gt;
&lt;li&gt;What would we do if the site were defaced or blocked tomorrow?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The answer does not need to be complicated. It does need to be specific.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Small Business Website Vulnerabilities
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How often should a small business update its website?
&lt;/h3&gt;

&lt;p&gt;Review website software monthly at minimum. Apply critical security patches as soon as they are available, especially when the affected software is internet-facing or accepts user input.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is a brochure website still at risk?
&lt;/h3&gt;

&lt;p&gt;Yes. A brochure site can still be abused if it has forms, admin access, plugins, scripts, a CMS, hosting credentials, or outdated dependencies. Static sites usually have a smaller attack surface, but they still need domain, hosting, DNS, and form security.&lt;/p&gt;

&lt;h3&gt;
  
  
  Will security updates hurt SEO?
&lt;/h3&gt;

&lt;p&gt;They should not if they are tested properly. The SEO risk comes from broken redirects, missing metadata, failed pages, blocked crawlers, broken images, bad canonicals, or forms that stop working after an update.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the fastest way to reduce risk this week?
&lt;/h3&gt;

&lt;p&gt;Remove unused plugins and accounts, enable multifactor authentication on admin accounts, verify backups, update critical software, and test the contact form. Those steps reduce common risk quickly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do small businesses need a vulnerability scanner?
&lt;/h3&gt;

&lt;p&gt;Many do, but a scanner is not a substitute for ownership. Scanners can find exposed software, missing headers, outdated dependencies, and common flaws. Someone still needs to review findings, prioritize fixes, and confirm the repair.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Website vulnerability management is now part of small business operations. The 2026 DBIR shows why: attackers are exploiting software flaws at scale, and the window to respond is getting shorter.&lt;/p&gt;

&lt;p&gt;You do not need enterprise complexity to improve security. You need a clear owner, a monthly review, fast critical patching, clean backups, limited admin access, dependency awareness, and testing after every meaningful change.&lt;/p&gt;

&lt;p&gt;That same discipline supports SEO, AEO, and GEO. A website that stays patched, stable, fast, and trustworthy is easier for customers to use, easier for search engines to crawl, and easier for AI answer systems to cite accurately.&lt;/p&gt;

&lt;p&gt;Echo Effect helps small businesses build and maintain websites with performance, search visibility, and practical security in mind. If your current site has no patch owner, no backup plan, or no clear inventory, start with a technical website audit before the next vulnerability turns into lost leads.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Cybersecurity and Infrastructure Security Agency, &amp;amp; Federal Bureau of Investigation. (2024a, March). &lt;em&gt;Secure by design alert: Eliminating SQL injection vulnerabilities in software&lt;/em&gt;. &lt;a href="https://www.ic3.gov/CSA/2024/240325.pdf" rel="noopener noreferrer"&gt;https://www.ic3.gov/CSA/2024/240325.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cybersecurity and Infrastructure Security Agency, &amp;amp; Federal Bureau of Investigation. (2024b, September). &lt;em&gt;Secure by design alert: Eliminating cross-site scripting vulnerabilities&lt;/em&gt;. &lt;a href="https://www.ic3.gov/CSA/2024/240917.pdf" rel="noopener noreferrer"&gt;https://www.ic3.gov/CSA/2024/240917.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OWASP Foundation. (2025a). &lt;em&gt;A01:2025 Broken access control&lt;/em&gt;. &lt;a href="https://owasp.org/Top10/2025/A01_2025-Broken_Access_Control/" rel="noopener noreferrer"&gt;https://owasp.org/Top10/2025/A01_2025-Broken_Access_Control/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OWASP Foundation. (2025b). &lt;em&gt;Introduction: OWASP Top 10:2025&lt;/em&gt;. &lt;a href="https://owasp.org/Top10/2025/0x00_2025-Introduction/" rel="noopener noreferrer"&gt;https://owasp.org/Top10/2025/0x00_2025-Introduction/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OWASP Foundation. (2025c). &lt;em&gt;A03:2025 Software supply chain failures&lt;/em&gt;. &lt;a href="https://owasp.org/Top10/2025/A03_2025-Software_Supply_Chain_Failures/" rel="noopener noreferrer"&gt;https://owasp.org/Top10/2025/A03_2025-Software_Supply_Chain_Failures/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Souppaya, M., Scarfone, K., &amp;amp; Dodson, D. (2022). &lt;em&gt;Secure Software Development Framework (SSDF) version 1.1: Recommendations for mitigating the risk of software vulnerabilities&lt;/em&gt; (NIST Special Publication 800-218). National Institute of Standards and Technology. &lt;a href="https://csrc.nist.gov/pubs/sp/800/218/final" rel="noopener noreferrer"&gt;https://csrc.nist.gov/pubs/sp/800/218/final&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verizon. (2026a). &lt;em&gt;2026 Data Breach Investigations Report&lt;/em&gt;. &lt;a href="https://www.verizon.com/business/resources/reports/dbir/" rel="noopener noreferrer"&gt;https://www.verizon.com/business/resources/reports/dbir/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verizon. (2026b, May). &lt;em&gt;Breach entry point, 2026 DBIR finds&lt;/em&gt;. &lt;a href="https://www.verizon.com/about/news/breach-industry-wide-dbir-finds" rel="noopener noreferrer"&gt;https://www.verizon.com/about/news/breach-industry-wide-dbir-finds&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>cybersecurity</category>
      <category>webdesign</category>
    </item>
    <item>
      <title>Should Small Businesses Block AI Crawlers in 2026?</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 18 Aug 2026 15:26:56 +0000</pubDate>
      <link>https://dev.to/rverwey/should-small-businesses-block-ai-crawlers-in-2026-3f43</link>
      <guid>https://dev.to/rverwey/should-small-businesses-block-ai-crawlers-in-2026-3f43</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.echoeffect.net/blog/ai-crawler-access-small-business-websites-2026" rel="noopener noreferrer"&gt;echoeffect.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI crawlers are no longer a side issue for publishers and large media companies. They are now part of how customers discover local services, compare businesses, ask buying questions, and decide which website is worth trusting.&lt;/p&gt;

&lt;p&gt;That creates a practical question for small business owners: should your website allow AI crawlers, block them, or split the difference?&lt;/p&gt;

&lt;p&gt;The short answer is this: most small businesses should allow search and user-requested AI crawlers that can send visibility back to the business, but they should be more cautious about training crawlers, unknown bots, and automated traffic that creates cost without a clear business return. The right answer is not "allow everything" or "block everything." It is a written access policy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; If your website depends on discovery, do not blindly block every AI crawler. Separate search, agent, and training use cases, then decide what each category is allowed to do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why AI Crawler Access Changed in 2026
&lt;/h2&gt;

&lt;p&gt;For years, the crawler bargain was easy to understand. Search engines crawled public pages, indexed them, and sent people back through organic search results. Website owners allowed crawling because the traffic was worth it.&lt;/p&gt;

&lt;p&gt;AI search complicates that bargain. Some bots crawl to build search indexes that can cite and link to your website. Some fetch pages because a user asked an assistant a specific question. Others collect public content for model training, where the business value to the website owner is harder to measure.&lt;/p&gt;

&lt;p&gt;Cloudflare framed this shift clearly in its July 1, 2026 update on AI traffic controls. It separated AI bot activity into three main use cases: Search, Agent, and Training. Search crawlers collect or index content so they can answer future questions. Agent traffic acts in real time on a person's behalf. Training crawlers collect content that may be absorbed into an AI model (Lee &amp;amp; Becker, 2026).&lt;/p&gt;

&lt;p&gt;That distinction matters. A small business may want ChatGPT, Perplexity, Claude, or Google to cite its service pages in answers. That same business may not want every training crawler copying its full blog archive forever.&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%2Fimages.unsplash.com%2Fphoto-1543286386-713bdd548da4%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1543286386-713bdd548da4%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Analytics dashboard with charts used to monitor crawler and search performance" width="1200" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI crawler policy should be tied to measurable visibility, traffic, server behavior, and lead quality.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three AI Bot Categories That Matter
&lt;/h2&gt;

&lt;p&gt;Small businesses do not need to memorize every user agent on the internet. They need a decision framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Search crawlers
&lt;/h3&gt;

&lt;p&gt;Search crawlers are the easiest category to justify allowing when visibility is the goal. These bots help AI-powered search products discover and cite websites.&lt;/p&gt;

&lt;p&gt;OpenAI's crawler documentation says &lt;code&gt;OAI-SearchBot&lt;/code&gt; is used to surface websites in ChatGPT search features. OpenAI also explains that site owners can allow &lt;code&gt;OAI-SearchBot&lt;/code&gt; for search visibility while disallowing &lt;code&gt;GPTBot&lt;/code&gt; for training use, because those settings are independent (OpenAI, n.d.).&lt;/p&gt;

&lt;p&gt;Perplexity documents a similar split. &lt;code&gt;PerplexityBot&lt;/code&gt; is designed to surface and link websites in Perplexity search results, while &lt;code&gt;Perplexity-User&lt;/code&gt; supports user-triggered fetches when someone asks a question (Perplexity, n.d.).&lt;/p&gt;

&lt;p&gt;For a small business website, search crawlers usually deserve access to public marketing pages, service pages, blog posts, case studies, reviews, and FAQs. Those are the pages that can earn citations, impressions, and qualified leads.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Agent and user-requested crawlers
&lt;/h3&gt;

&lt;p&gt;Agent traffic is different from background crawling. It may happen because a real person asks an AI assistant to compare providers, summarize a service page, check pricing, or find contact information.&lt;/p&gt;

&lt;p&gt;OpenAI says &lt;code&gt;ChatGPT-User&lt;/code&gt; is used for certain user actions in ChatGPT and Custom GPTs, is not automatic web crawling, and is not used to determine whether content appears in search (OpenAI, n.d.). Anthropic lists &lt;code&gt;Claude-User&lt;/code&gt; as user-directed retrieval and warns that disabling it may reduce visibility for user-directed web search (Anthropic, n.d.).&lt;/p&gt;

&lt;p&gt;This kind of traffic can be valuable because it may happen close to a buying decision. A customer might ask, "Find a Florida web design agency that works with small businesses and understands SEO." If an assistant cannot fetch your public pages, your business may not be considered.&lt;/p&gt;

&lt;p&gt;Agent traffic still needs guardrails. Forms, checkout flows, booking tools, and account areas should be protected from abuse. Public informational pages can usually be available.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Training crawlers
&lt;/h3&gt;

&lt;p&gt;Training crawlers are the most sensitive category. They collect content that may be used to improve AI foundation models. That may benefit the broader AI ecosystem, but the return to an individual small business is usually indirect.&lt;/p&gt;

&lt;p&gt;OpenAI describes &lt;code&gt;GPTBot&lt;/code&gt; as a crawler for content that may be used in training its generative AI foundation models. Anthropic describes &lt;code&gt;ClaudeBot&lt;/code&gt; as a crawler that collects web content that could contribute to model training (Anthropic, n.d.; OpenAI, n.d.).&lt;/p&gt;

&lt;p&gt;Some businesses will allow training crawlers because they want maximum exposure and do not publish sensitive or proprietary material. Others will block training crawlers while keeping search crawlers open. That is a reasonable middle ground.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robots.txt Is a Traffic Signal, Not a Security Wall
&lt;/h2&gt;

&lt;p&gt;The first tool most site owners hear about is &lt;code&gt;robots.txt&lt;/code&gt;. It is useful, but it is often misunderstood.&lt;/p&gt;

&lt;p&gt;Google Search Central explains that &lt;code&gt;robots.txt&lt;/code&gt; tells crawlers which URLs they can access and is mainly used to manage crawler traffic. Google is explicit that &lt;code&gt;robots.txt&lt;/code&gt; is not a mechanism for keeping a page out of Google Search results, and private material should be protected with stronger controls such as &lt;code&gt;noindex&lt;/code&gt; or password protection when appropriate (Google Search Central, 2025).&lt;/p&gt;

&lt;p&gt;The limitation is important: &lt;code&gt;robots.txt&lt;/code&gt; is a request. Respectable crawlers usually honor it. Bad or careless crawlers may ignore it.&lt;/p&gt;

&lt;p&gt;That means &lt;code&gt;robots.txt&lt;/code&gt; is good for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Expressing crawler policy.&lt;/li&gt;
&lt;li&gt;Reducing wasteful crawling.&lt;/li&gt;
&lt;li&gt;Allowing or disallowing named AI bots.&lt;/li&gt;
&lt;li&gt;Separating search crawlers from training crawlers when a vendor supports that split.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is not good for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Protecting confidential content.&lt;/li&gt;
&lt;li&gt;Stopping hostile scraping by itself.&lt;/li&gt;
&lt;li&gt;Blocking all bot traffic at the network level.&lt;/li&gt;
&lt;li&gt;Guaranteeing that a disallowed URL cannot appear anywhere online.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If information should not be public, it should not be protected only by &lt;code&gt;robots.txt&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Google Says About AI Search Visibility
&lt;/h2&gt;

&lt;p&gt;Google's guidance is useful because it cuts through a lot of bad advice. Google says the same foundational SEO best practices still apply to AI Overviews and AI Mode. Pages need to be crawlable, indexed, eligible for snippets, internally discoverable, useful to users, and supported by visible text, relevant media, and structured data that matches the visible content (Google Search Central, n.d.-a).&lt;/p&gt;

&lt;p&gt;Google also says there are no extra technical requirements to appear as a supporting link in AI Overviews or AI Mode, beyond being indexed and eligible for Google Search with a snippet (Google Search Central, n.d.-a).&lt;/p&gt;

&lt;p&gt;For crawler policy, this creates a simple rule: if you want Google Search and Google's AI features to understand a public page, do not block Googlebot from crawling it. Google says AI features in Search use Googlebot crawling controls, while snippet and preview controls such as &lt;code&gt;nosnippet&lt;/code&gt;, &lt;code&gt;data-nosnippet&lt;/code&gt;, &lt;code&gt;max-snippet&lt;/code&gt;, and &lt;code&gt;noindex&lt;/code&gt; limit what can be shown from pages (Google Search Central, n.d.-a).&lt;/p&gt;

&lt;p&gt;That is different from Google-Extended, which Google describes separately for limiting AI training and grounding in some other Google systems (Google Search Central, n.d.-a).&lt;/p&gt;

&lt;p&gt;The practical takeaway: do not confuse search visibility controls with training opt-out controls. They are related, but they are not the same decision.&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%2Fimages.unsplash.com%2Fphoto-1516321497487-e288fb19713f%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1516321497487-e288fb19713f%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Team reviewing website strategy around a laptop and printed notes" width="1200" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The best AI access policy is a business decision first, then a technical configuration.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical AI Crawler Policy for Small Businesses
&lt;/h2&gt;

&lt;p&gt;Here is a simple starting policy for a service business that wants visibility but does not want to give away control blindly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Allow search crawlers for public marketing content
&lt;/h3&gt;

&lt;p&gt;Allow crawlers that are explicitly tied to search discovery and citation, such as Googlebot, OAI-SearchBot, PerplexityBot, and other reputable search-oriented bots, unless you have a specific reason to block them.&lt;/p&gt;

&lt;p&gt;Public pages that should usually stay crawlable include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Homepage.&lt;/li&gt;
&lt;li&gt;Service pages.&lt;/li&gt;
&lt;li&gt;About page.&lt;/li&gt;
&lt;li&gt;Contact page.&lt;/li&gt;
&lt;li&gt;Blog posts.&lt;/li&gt;
&lt;li&gt;FAQs.&lt;/li&gt;
&lt;li&gt;Case studies and portfolio pages.&lt;/li&gt;
&lt;li&gt;Public reviews or testimonials.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These pages support SEO, AEO, and GEO because they tell search systems and answer engines who you are, what you do, where you serve customers, and why you are credible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consider blocking training crawlers if your content is proprietary
&lt;/h3&gt;

&lt;p&gt;If your site includes original research, paid resources, detailed templates, premium guides, proprietary methods, or content you do not want used for model training, consider blocking training-specific user agents while keeping search-specific crawlers available.&lt;/p&gt;

&lt;p&gt;This is the key nuance many businesses miss. Blocking every AI bot may reduce discoverability. Allowing every AI bot may give away more than the business intends. Splitting the policy by use case is the more mature option.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep user-requested fetchers available for public pages
&lt;/h3&gt;

&lt;p&gt;User-requested fetchers can help assistants answer questions about your business in the moment. For a small business, that can be valuable.&lt;/p&gt;

&lt;p&gt;The safer approach is to allow them to retrieve public content while protecting forms, private tools, admin routes, staging environments, and anything that should require authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use WAF and bot tools for enforcement
&lt;/h3&gt;

&lt;p&gt;When crawler behavior becomes abusive, use stronger controls than &lt;code&gt;robots.txt&lt;/code&gt;. A web application firewall, CDN bot management, rate limiting, and IP verification can help separate legitimate bots from spoofed user agents.&lt;/p&gt;

&lt;p&gt;Perplexity's documentation, for example, recommends using both user-agent and official IP range conditions when configuring WAF rules for its bots (Perplexity, n.d.). That same principle applies broadly: a user-agent string alone is easy to fake.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitor the outcome
&lt;/h3&gt;

&lt;p&gt;Crawler policy is not a one-time setting. Review it monthly or quarterly.&lt;/p&gt;

&lt;p&gt;Watch for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Drops in Google Search Console impressions.&lt;/li&gt;
&lt;li&gt;Important pages disappearing from AI search citations.&lt;/li&gt;
&lt;li&gt;Sudden spikes in bot traffic.&lt;/li&gt;
&lt;li&gt;Server load tied to suspicious crawlers.&lt;/li&gt;
&lt;li&gt;AI referrals that convert into leads.&lt;/li&gt;
&lt;li&gt;Branded search growth after AI visibility.&lt;/li&gt;
&lt;li&gt;Crawl errors caused by CDN or WAF rules.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Google says Search Console can measure performance in generative AI features and warns against relying on third-party tools that claim access to internal AI ranking systems (Google Search Central, n.d.-b). Treat your own lead data as the final test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Pay Per Crawl Fits
&lt;/h2&gt;

&lt;p&gt;Cloudflare introduced Pay Per Crawl in 2025 as a private beta that lets content owners allow, charge, or block AI crawler access. The system uses HTTP status code &lt;code&gt;402 Payment Required&lt;/code&gt; and gives publishers a way to set a price per request across a domain (Allen &amp;amp; Newton, 2025).&lt;/p&gt;

&lt;p&gt;For most small businesses, this is not the first move. A local service business usually makes money from being discovered, contacted, and hired, not from charging crawlers to read its service pages.&lt;/p&gt;

&lt;p&gt;But Pay Per Crawl matters as a signal. The web is moving toward more explicit access rules. Website owners are asking better questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Who is crawling my content?&lt;/li&gt;
&lt;li&gt;What are they using it for?&lt;/li&gt;
&lt;li&gt;Do they send users back?&lt;/li&gt;
&lt;li&gt;Do they respect my stated preferences?&lt;/li&gt;
&lt;li&gt;Can I measure the business return?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those questions are healthy, even if the answer for a small business is still "allow search, monitor agents, restrict training where appropriate."&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: AI Crawlers and Small Business Websites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Should small businesses block all AI crawlers?
&lt;/h3&gt;

&lt;p&gt;Usually, no. Blocking all AI crawlers can reduce visibility in AI-powered search and user-requested answers. Most small businesses should separate search crawlers, user-requested agents, and training crawlers, then make a different decision for each category.&lt;/p&gt;

&lt;h3&gt;
  
  
  Will blocking training crawlers hurt SEO?
&lt;/h3&gt;

&lt;p&gt;Not necessarily. Some vendors separate search and training crawlers. For example, OpenAI says site owners can allow &lt;code&gt;OAI-SearchBot&lt;/code&gt; while disallowing &lt;code&gt;GPTBot&lt;/code&gt;. The risk comes from blocking crawlers that are tied to search discovery or from blocking major search engines by mistake.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is robots.txt enough to protect private content?
&lt;/h3&gt;

&lt;p&gt;No. &lt;code&gt;robots.txt&lt;/code&gt; is not a security control. It communicates crawler preferences, but it does not hide private material from the web. Use authentication, password protection, &lt;code&gt;noindex&lt;/code&gt;, server rules, or access controls for content that should not be public.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Google require llms.txt for AI Overviews or AI Mode?
&lt;/h3&gt;

&lt;p&gt;No. Google says no new machine-readable file, AI text file, special AI markup, or special schema is required to appear in AI Overviews or AI Mode. Foundational SEO still matters most: crawlability, helpful content, internal links, page experience, visible text, relevant media, and accurate structured data (Google Search Central, n.d.-a).&lt;/p&gt;

&lt;h3&gt;
  
  
  What should a small business do this month?
&lt;/h3&gt;

&lt;p&gt;Review &lt;code&gt;robots.txt&lt;/code&gt;, confirm public pages are crawlable, decide whether training crawlers should be allowed, check CDN or WAF rules for accidental blocks, and monitor Search Console after any access change. The goal is controlled discoverability, not panic blocking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;AI crawler access is now part of SEO, AEO, and GEO strategy. It affects whether your business can be found, cited, summarized, compared, and recommended by AI-powered search tools.&lt;/p&gt;

&lt;p&gt;The smartest policy for most small businesses is selective access.&lt;/p&gt;

&lt;p&gt;Allow crawlers that support search visibility. Keep public pages available to user-requested assistants. Consider limiting training crawlers when your content is proprietary or when the business return is unclear. Use &lt;code&gt;robots.txt&lt;/code&gt; to state preferences, WAF rules to enforce suspicious traffic controls, and Search Console plus lead data to measure whether the policy is helping.&lt;/p&gt;

&lt;p&gt;Do not let fear make your business invisible. Do not let hype make your website a free-for-all. Treat crawler access like every other digital marketing decision: define the goal, measure the return, and adjust when the data changes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Echo Effect helps small businesses build websites that are readable by people, search engines, and AI answer systems. If your crawler policy, robots.txt file, or AI visibility strategy is unclear, schedule a discovery call and we will identify the highest-impact fixes first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Allen, W., &amp;amp; Newton, S. (2025, July 1). &lt;em&gt;Introducing pay per crawl: Enabling content owners to charge AI crawlers for access&lt;/em&gt;. Cloudflare. &lt;a href="https://blog.cloudflare.com/introducing-pay-per-crawl/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/introducing-pay-per-crawl/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anthropic. (n.d.). &lt;em&gt;Does Anthropic crawl data from the web, and how can site owners block the crawler?&lt;/em&gt; Claude Help Center. Retrieved July 13, 2026, from &lt;a href="https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (n.d.-a). &lt;em&gt;AI features and your website&lt;/em&gt;. Google for Developers. Retrieved July 13, 2026, from &lt;a href="https://developers.google.com/search/docs/appearance/ai-features" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/appearance/ai-features&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (n.d.-b). &lt;em&gt;Optimizing your website for generative AI features on Google Search&lt;/em&gt;. Google for Developers. Retrieved July 13, 2026, from &lt;a href="https://developers.google.com/search/docs/fundamentals/ai-optimization-guide" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/fundamentals/ai-optimization-guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (2025, December 10). &lt;em&gt;Robots.txt introduction and guide&lt;/em&gt;. Google for Developers. &lt;a href="https://developers.google.com/search/docs/crawling-indexing/robots/intro" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/crawling-indexing/robots/intro&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lee, J.-H., &amp;amp; Becker, B. (2026, July 1). &lt;em&gt;Your site, your rules: New AI traffic options for all customers&lt;/em&gt;. Cloudflare. &lt;a href="https://blog.cloudflare.com/content-independence-day-ai-options/" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/content-independence-day-ai-options/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OpenAI. (n.d.). &lt;em&gt;Overview of OpenAI crawlers&lt;/em&gt;. OpenAI Developers. Retrieved July 13, 2026, from &lt;a href="https://developers.openai.com/api/docs/bots" rel="noopener noreferrer"&gt;https://developers.openai.com/api/docs/bots&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perplexity. (n.d.). &lt;em&gt;Perplexity crawlers&lt;/em&gt;. Perplexity Docs. Retrieved July 13, 2026, from &lt;a href="https://docs.perplexity.ai/docs/resources/perplexity-crawlers" rel="noopener noreferrer"&gt;https://docs.perplexity.ai/docs/resources/perplexity-crawlers&lt;/a&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>ai</category>
      <category>webdev</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Interop 2026 Website Upgrades for Small Businesses</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 18 Aug 2026 15:26:52 +0000</pubDate>
      <link>https://dev.to/rverwey/interop-2026-website-upgrades-for-small-businesses-30ba</link>
      <guid>https://dev.to/rverwey/interop-2026-website-upgrades-for-small-businesses-30ba</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.echoeffect.net/blog/interop-2026-small-business-website-upgrades" rel="noopener noreferrer"&gt;echoeffect.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Interop 2026 is one of the most practical web development stories of the year because it is not about one framework, one browser, or one vendor. It is about making important web platform features work more consistently across Chrome, Edge, Firefox, and Safari.&lt;/p&gt;

&lt;p&gt;For small businesses, that matters more than it sounds. Browser inconsistency turns into expensive rework, broken forms, awkward mobile menus, glitchy popups, unreliable animations, and website features that behave differently for different customers.&lt;/p&gt;

&lt;p&gt;As of July 6, 2026, the smart move is not to chase every new feature. The smart move is to modernize around features that are becoming reliable, supported, and useful for real customer journeys.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Interop 2026 helps browser teams improve the same high-priority web features during the same year. Small businesses should use it as a signal to plan safer upgrades for menus, dialogs, page transitions, responsive layouts, mobile behavior, accessibility, and AI-search-ready content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is Interop 2026?
&lt;/h2&gt;

&lt;p&gt;Interop 2026 is a coordinated cross-browser effort run by representatives from major browser engine contributors, including Apple, Google, Igalia, Microsoft, and Mozilla. The project selects focus areas that matter to developers and users, then tracks browser progress through automated Web Platform Tests (Andrew, 2026; Web Platform Tests, 2026).&lt;/p&gt;

&lt;p&gt;The 2026 focus areas include features such as anchor positioning, container style queries, dialogs and popovers, view transitions, scroll-driven animations, scroll snap, web compatibility fixes, WebRTC, WebTransport, and mobile testing work (Web Platform Tests, 2026; Wu &amp;amp; Simmons, 2026).&lt;/p&gt;

&lt;p&gt;That list may sound technical, but the business outcome is simple: websites should be easier to build once and trust across modern browsers.&lt;/p&gt;

&lt;p&gt;That is especially useful for small business sites because customers do not care which browser caused a bug. If a menu fails on iPhone, a booking form shifts on Android, or a modal traps keyboard focus on desktop, the business owns the bad experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Baseline Belongs in the Same Conversation
&lt;/h2&gt;

&lt;p&gt;Interop is about improving cross-browser consistency. Baseline is about knowing when a web platform feature is ready to use.&lt;/p&gt;

&lt;p&gt;web.dev explains that Baseline gives developers clear information about which features are supported across the core browser set: Chrome, Edge, Firefox, and Safari on desktop and mobile. A feature can be "newly available" when all core browsers support it, then "widely available" after 30 months have passed (Google Chrome Developers, n.d.).&lt;/p&gt;

&lt;p&gt;For a business owner, Baseline is useful because it turns a vague question into a practical one.&lt;/p&gt;

&lt;p&gt;Instead of asking, "Can our website use this new feature?" ask:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Is it Baseline?&lt;/li&gt;
&lt;li&gt;Is it supported by the browsers our customers actually use?&lt;/li&gt;
&lt;li&gt;Does it improve conversion, accessibility, performance, or maintenance?&lt;/li&gt;
&lt;li&gt;Can we ship it without adding heavy JavaScript?&lt;/li&gt;
&lt;li&gt;Can we keep a simple fallback for older browsers?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That mindset prevents two common mistakes: using outdated techniques forever because they feel safe, or adopting new features too early because they feel exciting.&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%2Fimages.unsplash.com%2Fphoto-1517180102446-f3ece451e9d8%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1517180102446-f3ece451e9d8%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Developer reviewing website code on a laptop during a browser compatibility update" width="1200" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Modern web upgrades should reduce complexity, not add it. Interop and Baseline help teams choose native browser features with stronger support.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Small Business Website Upgrades Worth Watching
&lt;/h2&gt;

&lt;p&gt;Not every Interop 2026 focus area belongs on a brochure site. A small business website does not need experimental complexity to look modern. It needs dependable navigation, clear content, fast pages, usable forms, accessible interactions, and crawlable answers.&lt;/p&gt;

&lt;p&gt;These are the areas most likely to matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Better Popups, Dialogs, and Menus
&lt;/h3&gt;

&lt;p&gt;Dialogs and popovers are part of the Interop 2026 focus list. The work includes improvements around the &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element and Popover API, including open states and behavior for subordinate popovers (Andrew, 2026).&lt;/p&gt;

&lt;p&gt;That matters because many websites still use custom JavaScript for dropdowns, modals, tooltips, announcement bars, cookie notices, quote prompts, and mobile navigation. Custom overlays are easy to get wrong. They can trap focus, block content, fail screen readers, or create layout shifts.&lt;/p&gt;

&lt;p&gt;Native browser primitives can reduce that risk when used carefully. For small businesses, the priority should be practical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mobile menus that open and close predictably.&lt;/li&gt;
&lt;li&gt;Quote request popups that do not block the whole page.&lt;/li&gt;
&lt;li&gt;Tooltips that support keyboard and touch users.&lt;/li&gt;
&lt;li&gt;Cookie notices that do not cover important actions.&lt;/li&gt;
&lt;li&gt;Form dialogs that keep focus where users expect it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to add more popups. The goal is to make necessary overlays less fragile.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. More Reliable Responsive Layouts
&lt;/h3&gt;

&lt;p&gt;Container style queries and anchor positioning are also Interop 2026 focus areas. Container style queries let styles respond to a container's properties rather than only the viewport. Anchor positioning lets one element be positioned relative to another, such as placing a tooltip beside the field it explains (Andrew, 2026; Web Platform Tests, 2026).&lt;/p&gt;

&lt;p&gt;For small business websites, this can make component design more reliable. Service cards, pricing tables, testimonial blocks, FAQ sections, and lead forms often appear in different layouts across the site. A component that adapts based on its own container can be easier to reuse without layout hacks.&lt;/p&gt;

&lt;p&gt;That can improve maintainability and page speed. When native CSS handles layout decisions, a site may need less JavaScript and fewer brittle breakpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Cleaner Page Transitions
&lt;/h3&gt;

&lt;p&gt;View transitions continued from prior Interop work into 2026. WebKit notes that cross-document view transitions can create smoother animated transitions between pages, reducing abrupt jumps when users navigate a site (Wu &amp;amp; Simmons, 2026).&lt;/p&gt;

&lt;p&gt;This is not a license to animate everything. Overdone motion hurts usability.&lt;/p&gt;

&lt;p&gt;Used carefully, page transitions can make service pages, galleries, product pages, and portfolio pages feel smoother without turning the site into a heavy app. They can also help preserve orientation when users move through related pages.&lt;/p&gt;

&lt;p&gt;The practical rule is simple: motion should clarify the experience. If it distracts from the call to action, remove it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Stronger Mobile Testing
&lt;/h3&gt;

&lt;p&gt;Interop 2026 includes mobile testing as an investigation area. WebKit specifically points to mobile-specific infrastructure work for dynamic viewport changes, which are crucial for responsive mobile web experiences (Wu &amp;amp; Simmons, 2026).&lt;/p&gt;

&lt;p&gt;That matters because small business traffic often comes from mobile moments: someone needs a quote, checks reviews, looks up hours, compares services, or tries to tap a phone number.&lt;/p&gt;

&lt;p&gt;A mobile site should pass these checks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first screen explains what the business does.&lt;/li&gt;
&lt;li&gt;The primary action is visible and easy to tap.&lt;/li&gt;
&lt;li&gt;Forms do not jump when the keyboard opens.&lt;/li&gt;
&lt;li&gt;Sticky headers do not hide content.&lt;/li&gt;
&lt;li&gt;Menus work with touch, keyboard, and screen readers.&lt;/li&gt;
&lt;li&gt;Images are sharp but not oversized.&lt;/li&gt;
&lt;li&gt;Contact information is crawlable text.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mobile is not a smaller desktop site. It is often the main sales path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How This Supports SEO, AEO, and GEO
&lt;/h2&gt;

&lt;p&gt;Interop and Baseline are web development topics, but they directly affect search visibility.&lt;/p&gt;

&lt;p&gt;Google Search Central says Core Web Vitals measure real-world user experience for loading performance, interactivity, and visual stability. Google recommends good Core Web Vitals for Search and general user experience, with LCP at 2.5 seconds or faster, INP under 200 milliseconds, and CLS below 0.1 (Google Search Central, 2025).&lt;/p&gt;

&lt;p&gt;Modern native features can help when they replace heavy scripts, reduce layout hacks, and make pages easier to interact with. Faster, more stable pages support SEO because users and crawlers can access content with less friction.&lt;/p&gt;

&lt;p&gt;They also support AEO and GEO.&lt;/p&gt;

&lt;p&gt;Google's guidance for AI features in Search says existing SEO fundamentals remain relevant for AI Overviews and AI Mode. Site owners should allow crawling, make content easy to find through internal links, provide a good page experience, keep important content available in text, support content with useful images and videos, and make sure structured data matches visible text (Google Search Central, n.d.).&lt;/p&gt;

&lt;p&gt;That means an AI-ready website still needs old-fashioned discipline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clear HTML content.&lt;/li&gt;
&lt;li&gt;Descriptive headings.&lt;/li&gt;
&lt;li&gt;Useful internal links.&lt;/li&gt;
&lt;li&gt;Fast pages.&lt;/li&gt;
&lt;li&gt;Accurate structured data.&lt;/li&gt;
&lt;li&gt;Real author attribution.&lt;/li&gt;
&lt;li&gt;Original answers to customer questions.&lt;/li&gt;
&lt;li&gt;Images that support the page topic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The future of search is not only about prompts. It is also about whether your website gives machines and people clean, trustworthy information.&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%2Fimages.unsplash.com%2Fphoto-1454165804606-c3d57bc86b40%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1454165804606-c3d57bc86b40%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Business owner planning website improvements with analytics, laptop, and printed documents" width="1200" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The best website upgrades connect platform changes to measurable outcomes: faster pages, clearer answers, better leads, and fewer browser-specific bugs.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Upgrade Checklist
&lt;/h2&gt;

&lt;p&gt;Use this checklist before adding new web platform features to a small business website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Audit the Browser Risk
&lt;/h3&gt;

&lt;p&gt;Check analytics to see the browsers, devices, and operating systems your customers actually use. A feature that works well for a developer's desktop setup may still need testing on Safari for iOS, Chrome for Android, Edge on Windows, and Firefox.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prefer Baseline Features
&lt;/h3&gt;

&lt;p&gt;Start with features marked Baseline when possible. If a feature is newly available, test it carefully and provide a fallback. If it has limited availability, avoid using it for essential conversion paths unless there is a strong reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  Replace JavaScript Only When the Native Feature Is Better
&lt;/h3&gt;

&lt;p&gt;Native does not automatically mean better. A native dialog used poorly is still a poor experience. The right test is whether the change improves performance, accessibility, maintainability, or user clarity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Money Pages First
&lt;/h3&gt;

&lt;p&gt;Do not limit compatibility testing to the homepage. Test the pages that create business value:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Primary service pages.&lt;/li&gt;
&lt;li&gt;Contact page.&lt;/li&gt;
&lt;li&gt;Quote request forms.&lt;/li&gt;
&lt;li&gt;Booking pages.&lt;/li&gt;
&lt;li&gt;Paid ad landing pages.&lt;/li&gt;
&lt;li&gt;Blog posts that attract search traffic.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the homepage works but the lead form fails, the site still fails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep Content Visible as Text
&lt;/h3&gt;

&lt;p&gt;Do not hide important service details inside images, animations, tabs that never render server-side, or scripts that crawlers may struggle to process. If the information matters to customers, write it as visible text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measure Before and After
&lt;/h3&gt;

&lt;p&gt;Before shipping upgrades, record Core Web Vitals, crawlability, form completion behavior, and conversion rates. After shipping, measure again. A modern implementation that worsens INP or lead flow is not an upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Interop 2026 and Small Business Websites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Interop 2026 mean every browser supports the same features now?
&lt;/h3&gt;

&lt;p&gt;No. Interop 2026 is an active effort to improve selected focus areas during 2026. Use it as a planning signal, then verify current browser support before shipping important features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Baseline the same as Interop?
&lt;/h3&gt;

&lt;p&gt;No. Interop coordinates browser work on high-priority focus areas. Baseline helps developers understand whether a feature is ready to use across the core browser set.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should a small business redesign its website because of Interop 2026?
&lt;/h3&gt;

&lt;p&gt;Not automatically. Interop 2026 is a reason to review outdated patterns and plan safer upgrades. A redesign makes sense when your current site is slow, hard to update, difficult to use on mobile, or unreliable across browsers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which upgrades are most useful for lead generation?
&lt;/h3&gt;

&lt;p&gt;Focus on reliable mobile navigation, faster pages, accessible dialogs, stable forms, clear service content, and crawlable FAQ sections. Those improvements support both customer experience and search visibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do AI search tools care about modern browser features?
&lt;/h3&gt;

&lt;p&gt;AI search tools care most about accessible, crawlable, helpful content. Modern browser features help when they make content easier to reach, reduce friction, improve page experience, and keep important information available as text.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Interop 2026 is a reminder that the web platform keeps improving, and small business websites should not be frozen in old patterns forever.&lt;/p&gt;

&lt;p&gt;The right approach is selective modernization. Use Baseline to choose safer features. Use Interop 2026 to understand where browser reliability is improving. Test the customer journey on real devices. Measure Core Web Vitals. Keep service information visible, structured, and easy to cite.&lt;/p&gt;

&lt;p&gt;That combination supports SEO, AEO, and GEO because it gives search engines, answer engines, AI systems, and customers the same thing: a fast, trustworthy website that clearly explains what the business does and how to take the next step.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Andrew, R. (2026, February 12). &lt;em&gt;Interop 2026: Continuing to improve the web for developers&lt;/em&gt;. web.dev. &lt;a href="https://web.dev/blog/interop-2026" rel="noopener noreferrer"&gt;https://web.dev/blog/interop-2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Chrome Developers. (n.d.). &lt;em&gt;Baseline&lt;/em&gt;. web.dev. &lt;a href="https://web.dev/baseline" rel="noopener noreferrer"&gt;https://web.dev/baseline&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (n.d.). &lt;em&gt;AI features and your website&lt;/em&gt;. Google for Developers. &lt;a href="https://developers.google.com/search/docs/appearance/ai-features" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/appearance/ai-features&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (2025, December 10). &lt;em&gt;Understanding Core Web Vitals and Google search results&lt;/em&gt;. Google for Developers. &lt;a href="https://developers.google.com/search/docs/appearance/core-web-vitals" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/appearance/core-web-vitals&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Web Platform Tests. (2026). &lt;em&gt;Interop 2026&lt;/em&gt;. GitHub. &lt;a href="https://github.com/web-platform-tests/interop/blob/main/2026/README.md" rel="noopener noreferrer"&gt;https://github.com/web-platform-tests/interop/blob/main/2026/README.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wu, Y., &amp;amp; Simmons, J. (2026, February 12). &lt;em&gt;Announcing Interop 2026&lt;/em&gt;. WebKit. &lt;a href="https://webkit.org/blog/17818/announcing-interop-2026/" rel="noopener noreferrer"&gt;https://webkit.org/blog/17818/announcing-interop-2026/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>css</category>
      <category>webdesign</category>
    </item>
    <item>
      <title>Core Web Vitals Checklist for Small Business Websites</title>
      <dc:creator>Ryan VerWey</dc:creator>
      <pubDate>Tue, 18 Aug 2026 15:26:18 +0000</pubDate>
      <link>https://dev.to/rverwey/core-web-vitals-checklist-for-small-business-websites-4ef7</link>
      <guid>https://dev.to/rverwey/core-web-vitals-checklist-for-small-business-websites-4ef7</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://www.echoeffect.net/blog/core-web-vitals-small-business-checklist-2026" rel="noopener noreferrer"&gt;echoeffect.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Core Web Vitals are still one of the clearest ways to tell whether a small business website feels fast, stable, and easy to use. They are not the whole SEO story, but they are a practical signal because they measure what real visitors experience: loading speed, responsiveness, and visual stability.&lt;/p&gt;

&lt;p&gt;As of June 29, 2026, the three Core Web Vitals that matter most are Largest Contentful Paint, Interaction to Next Paint, and Cumulative Layout Shift. Google recommends checking those metrics at the 75th percentile of page loads, segmented across mobile and desktop visits (Google Search Central, n.d.; Walton, 2024).&lt;/p&gt;

&lt;p&gt;For small businesses, this is not just a technical scorecard. A slow homepage can waste ad spend. A sticky navigation menu can frustrate mobile visitors. A jumpy contact form can cost leads. A page that loads poorly can also weaken the clarity signals that search engines, answer engines, and AI crawlers use to understand and cite your site.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Aim for LCP at 2.5 seconds or faster, INP at 200 milliseconds or faster, and CLS at 0.1 or lower. Then test the actual lead path, not only the homepage.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Core Web Vitals Measure
&lt;/h2&gt;

&lt;p&gt;Core Web Vitals are a subset of Google's broader Web Vitals program. They focus on three user experience questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How quickly does the main content load?&lt;/li&gt;
&lt;li&gt;How quickly does the page respond after someone interacts?&lt;/li&gt;
&lt;li&gt;Does the layout stay stable while the page loads?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Largest Contentful Paint, or LCP, measures loading performance. A good LCP is 2.5 seconds or faster. Interaction to Next Paint, or INP, measures responsiveness after user input. A good INP is 200 milliseconds or faster. Cumulative Layout Shift, or CLS, measures unexpected visual movement. A good CLS is 0.1 or lower (Walton, 2024).&lt;/p&gt;

&lt;p&gt;Those numbers matter because they turn vague complaints into specific action. "The site feels slow" becomes "the hero image is pushing LCP past 4 seconds on mobile." "The form feels laggy" becomes "the first tap is waiting on heavy JavaScript." "The page jumps" becomes "images and embedded widgets do not reserve space before loading."&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%2Fimages.unsplash.com%2Fphoto-1504384308090-c894fdcc538d%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1504384308090-c894fdcc538d%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="People working on laptops in a modern office during a website performance review" width="1200" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Core Web Vitals are useful because they connect technical decisions to visible customer experience: faster pages, steadier layouts, and smoother interactions.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for SEO, AEO, and GEO
&lt;/h2&gt;

&lt;p&gt;Google's page experience guidance says Core Web Vitals are part of evaluating page experience, alongside factors such as mobile usability, HTTPS, and avoiding intrusive interstitials. Google also makes clear that helpful content remains central, but a good page experience can help content perform better when pages are otherwise similar (Google Search Central, n.d.).&lt;/p&gt;

&lt;p&gt;That is the SEO layer. The answer engine optimization and generative engine optimization layers are just as important.&lt;/p&gt;

&lt;p&gt;Answer engines need clean, readable pages that directly answer questions. Generative AI systems need content that is crawlable, structured, accurate, and easy to parse. Google's guidance for AI features says site owners should continue following search fundamentals, make important content available in text, keep structured data aligned with visible content, and support content with useful images or video where appropriate (Google Search Central, n.d.).&lt;/p&gt;

&lt;p&gt;Core Web Vitals do not guarantee AI citations. They do make your content easier to access and trust. A fast, stable, crawlable page with clear headings, direct answers, and real sources is more citation-friendly than a slow page buried behind layout shifts and heavy scripts.&lt;/p&gt;

&lt;p&gt;For the broader search strategy, pair this checklist with the &lt;a href="https://dev.to/blog/google-search-console-guide"&gt;Google Search Console guide&lt;/a&gt;, the &lt;a href="https://dev.to/blog/answer-engine-optimization-2026"&gt;answer engine optimization guide&lt;/a&gt;, and the &lt;a href="https://dev.to/blog/generative-engine-optimization-guide"&gt;generative engine optimization guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 Core Web Vitals Checklist
&lt;/h2&gt;

&lt;p&gt;Use this checklist when reviewing a small business website, especially before redesigning, buying ads, or publishing a new service page.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Test Real Field Data First
&lt;/h3&gt;

&lt;p&gt;Start with field data, not lab data. Field data reflects real users, devices, networks, and pages. Google's PageSpeed Insights reports field data from the Chrome User Experience Report when enough data is available, plus lab diagnostics from Lighthouse (Google PageSpeed Insights Team, n.d.).&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Homepage.&lt;/li&gt;
&lt;li&gt;Primary service pages.&lt;/li&gt;
&lt;li&gt;Contact page.&lt;/li&gt;
&lt;li&gt;Blog posts that bring organic traffic.&lt;/li&gt;
&lt;li&gt;Landing pages used for ads.&lt;/li&gt;
&lt;li&gt;Product or booking pages if the site has them.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The homepage may pass while a money page fails. Do not stop after one URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fix LCP by Prioritizing the Main Content
&lt;/h3&gt;

&lt;p&gt;LCP usually points to the largest visible element in the first viewport. On small business websites, that is often a hero image, heading block, background image, or large service-card section.&lt;/p&gt;

&lt;p&gt;Common LCP fixes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compress and resize hero images.&lt;/li&gt;
&lt;li&gt;Use modern image formats such as WebP or AVIF when possible.&lt;/li&gt;
&lt;li&gt;Avoid loading huge desktop images on mobile.&lt;/li&gt;
&lt;li&gt;Preload the most important above-the-fold image when appropriate.&lt;/li&gt;
&lt;li&gt;Reduce slow server response time.&lt;/li&gt;
&lt;li&gt;Remove render-blocking scripts and styles where practical.&lt;/li&gt;
&lt;li&gt;Keep the first viewport focused, not overloaded with sliders, videos, and popups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For many local business sites, the biggest win is simple: use one strong hero image, size it correctly, and avoid making the browser download five decorative assets before the visitor can read the offer.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Fix INP by Reducing JavaScript Pressure
&lt;/h3&gt;

&lt;p&gt;INP replaced First Input Delay as a Core Web Vital because it measures responsiveness across the full page visit, not only the first interaction. web.dev explains that INP observes interactions such as clicks, taps, and keyboard input, then reports a high-percentile interaction latency for the page (Wagner &amp;amp; Pollard, 2025).&lt;/p&gt;

&lt;p&gt;Poor INP often comes from too much JavaScript competing for the main thread. That can happen when a site loads heavy tracking tags, chat widgets, animation libraries, booking embeds, cookie banners, or large client-side frameworks on pages that do not need them.&lt;/p&gt;

&lt;p&gt;Improve INP by asking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does this script help the visitor complete the task?&lt;/li&gt;
&lt;li&gt;Does it need to load on every page?&lt;/li&gt;
&lt;li&gt;Can it load after the main content?&lt;/li&gt;
&lt;li&gt;Can this interaction be simpler?&lt;/li&gt;
&lt;li&gt;Can server-rendered HTML replace client-side rendering?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This matters for conversions. A visitor who taps "Request a Quote" should not wait because the browser is busy running a carousel script, three trackers, and an unused animation bundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Fix CLS by Reserving Space
&lt;/h3&gt;

&lt;p&gt;CLS is about unexpected movement. It usually shows up when images, ads, embeds, fonts, banners, or late-loading content shift the page after the visitor has started reading or tapping.&lt;/p&gt;

&lt;p&gt;Common CLS fixes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set width and height for images and videos.&lt;/li&gt;
&lt;li&gt;Reserve space for review widgets, maps, forms, and embedded calendars.&lt;/li&gt;
&lt;li&gt;Avoid injecting banners above existing content after load.&lt;/li&gt;
&lt;li&gt;Use font loading strategies that prevent dramatic text reflow.&lt;/li&gt;
&lt;li&gt;Keep sticky headers and mobile menus predictable.&lt;/li&gt;
&lt;li&gt;Test the page on real mobile widths, not only a desktop browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLS is especially important on lead forms. If the submit button moves while someone is trying to tap it, that is not a minor design issue. It is a conversion problem.&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%2Fimages.unsplash.com%2Fphoto-1517245386807-bb43f82c33c4%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1517245386807-bb43f82c33c4%3Fauto%3Dformat%26fit%3Dcrop%26w%3D1200%26q%3D80" alt="Website planning session with a laptop, notebook, and mobile device" width="1200" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Performance work should include the full customer journey: landing page, service details, contact form, confirmation page, and follow-up tracking.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Audit Third-Party Tools Like Business Costs
&lt;/h3&gt;

&lt;p&gt;Small business sites often collect third-party tools over time: analytics, heatmaps, chat widgets, booking tools, review embeds, social feeds, CRM forms, ad pixels, and cookie consent scripts.&lt;/p&gt;

&lt;p&gt;Some are worth it. Some are silently slowing down the site.&lt;/p&gt;

&lt;p&gt;Review each tool with four questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does it support revenue, measurement, compliance, or customer service?&lt;/li&gt;
&lt;li&gt;Is it still used by the business?&lt;/li&gt;
&lt;li&gt;Does it need to load on every page?&lt;/li&gt;
&lt;li&gt;Is there a lighter way to achieve the same result?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Performance best practice is not "remove every script." It is "make every script justify its place."&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Keep Mobile as the Default Test Case
&lt;/h3&gt;

&lt;p&gt;Most small business searches start in impatient moments: someone needs a contractor, restaurant, consultant, repair service, clinic, or local expert. They are often on a phone, using a cellular connection, and comparing options quickly.&lt;/p&gt;

&lt;p&gt;That means mobile performance deserves priority.&lt;/p&gt;

&lt;p&gt;Check whether:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first viewport explains what the business does.&lt;/li&gt;
&lt;li&gt;The main call to action is easy to tap.&lt;/li&gt;
&lt;li&gt;The phone number or contact path is visible.&lt;/li&gt;
&lt;li&gt;Text is readable without zooming.&lt;/li&gt;
&lt;li&gt;Menus respond quickly.&lt;/li&gt;
&lt;li&gt;Forms are short and stable.&lt;/li&gt;
&lt;li&gt;Images are sharp but not oversized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good mobile performance supports SEO, but it also supports the basic sales path. People do not wait patiently for a slow site when competitors are one tap away.&lt;/p&gt;

&lt;h2&gt;
  
  
  AEO and GEO Formatting Tips for Performance Pages
&lt;/h2&gt;

&lt;p&gt;Technical performance content can become too vague for AI systems to summarize well. Structure matters.&lt;/p&gt;

&lt;p&gt;For service pages and blog posts, use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Direct answers near the top of the page.&lt;/li&gt;
&lt;li&gt;Clear H2 and H3 headings.&lt;/li&gt;
&lt;li&gt;Short definitions for LCP, INP, and CLS.&lt;/li&gt;
&lt;li&gt;Specific thresholds and dates.&lt;/li&gt;
&lt;li&gt;Step-by-step checklists.&lt;/li&gt;
&lt;li&gt;Internal links to related SEO and web design resources.&lt;/li&gt;
&lt;li&gt;APA-style references for factual claims.&lt;/li&gt;
&lt;li&gt;Descriptive image alt text.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That format helps human readers skim, helps search engines classify the page, and helps AI systems extract accurate answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ: Core Web Vitals for Small Businesses
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do Core Web Vitals directly affect Google rankings?
&lt;/h3&gt;

&lt;p&gt;Core Web Vitals are part of Google's page experience signals. They are not a substitute for helpful content, relevance, authority, or local trust, but they can matter when users and search systems compare similar pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  What score should a small business website aim for?
&lt;/h3&gt;

&lt;p&gt;Aim for LCP at 2.5 seconds or faster, INP at 200 milliseconds or faster, and CLS at 0.1 or lower at the 75th percentile of page loads. Check both mobile and desktop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is PageSpeed Insights enough?
&lt;/h3&gt;

&lt;p&gt;PageSpeed Insights is a strong starting point, especially when it has field data. For a fuller picture, also check Search Console's Core Web Vitals report, Lighthouse diagnostics, analytics behavior, and real lead-flow testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I redesign my website if Core Web Vitals are poor?
&lt;/h3&gt;

&lt;p&gt;Not always. Some sites need targeted fixes: better images, fewer scripts, cleaner hosting, or reserved layout space. A full redesign makes sense when the site is structurally slow, hard to maintain, or failing the customer journey.&lt;/p&gt;

&lt;h3&gt;
  
  
  How often should Core Web Vitals be checked?
&lt;/h3&gt;

&lt;p&gt;Check monthly, after major content or design changes, and before spending heavily on ads. Also check after adding third-party scripts such as chat, booking, reviews, analytics, or social embeds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Core Web Vitals are not vanity metrics. They are a practical way to measure whether your website is fast enough, responsive enough, and stable enough for real customers.&lt;/p&gt;

&lt;p&gt;For small businesses, the best approach is focused: test the pages that make money, fix the biggest blockers first, keep mobile users in mind, and remove scripts or design choices that do not support the customer journey.&lt;/p&gt;

&lt;p&gt;Strong SEO, AEO, and GEO all start with the same foundation: helpful content on a website that people and crawlers can access without friction. If your site is slow, jumpy, or frustrating on mobile, a Core Web Vitals audit is one of the highest-value technical reviews you can run this year.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Google PageSpeed Insights Team. (n.d.). &lt;em&gt;About PageSpeed Insights&lt;/em&gt;. Google for Developers. &lt;a href="https://developers.google.com/speed/docs/insights/v5/about" rel="noopener noreferrer"&gt;https://developers.google.com/speed/docs/insights/v5/about&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (n.d.). &lt;em&gt;Understanding page experience in Google Search results&lt;/em&gt;. Google for Developers. &lt;a href="https://developers.google.com/search/docs/appearance/page-experience" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/appearance/page-experience&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google Search Central. (n.d.). &lt;em&gt;AI features and your website&lt;/em&gt;. Google for Developers. &lt;a href="https://developers.google.com/search/docs/appearance/ai-features" rel="noopener noreferrer"&gt;https://developers.google.com/search/docs/appearance/ai-features&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wagner, J., &amp;amp; Pollard, B. (2025, September 2). &lt;em&gt;Interaction to Next Paint (INP)&lt;/em&gt;. web.dev. &lt;a href="https://web.dev/articles/inp" rel="noopener noreferrer"&gt;https://web.dev/articles/inp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Walton, P. (2024, September 17). &lt;em&gt;Web Vitals&lt;/em&gt;. web.dev. &lt;a href="https://web.dev/articles/vitals" rel="noopener noreferrer"&gt;https://web.dev/articles/vitals&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>performance</category>
      <category>webdesign</category>
    </item>
  </channel>
</rss>
