<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Andrew Stiefel</title>
 <link href="https://andrewstiefel.com/feed.xml" rel="self"/>
 <link href="https://andrewstiefel.com/" rel="alternate"/>
 <subtitle>Hey, I'm Andrew Stiefel. Welcome to my digital garden, a slowly growing collection of ideas in the form of working notes and narrative essays.</subtitle>
 <updated>2026-05-25T11:11:05-07:00</updated>
 <id>https://andrewstiefel.com/</id>
 <author>
   <name>Andrew Stiefel</name>
   <email></email>
 </author>
 <rights type="text">Copyright © 2026 {"name" => "Andrew Stiefel", "url" => "https://andrewstiefel.com", "linkedin" => "andrewstiefel", "codeberg" => "andrewstiefel"}. All rights reserved.</rights>

 
 <entry>
   <title>Building a personal monorepo for writing</title>
   <link rel="alternate" href="https://andrewstiefel.com/monorepo/"/>
   <published>2025-07-19T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/personal-monorepo</id>
   <summary>How I created a workflow for researching and blogging with Obsidian and Jekyll</summary>
   <content type="html">&lt;p&gt;I use &lt;a href=&quot;https://obsidian.md/&quot;&gt;Obsidian&lt;/a&gt; to organize my thinking and writing. But I’ve always been dissatisfied with the process of turning what I write into a formatted post for my website. I either had to manage multiple vaults—adding complexity and violating one of my core principles of note-taking—or copy, paste, and edit my writing in another tool like VS Code.&lt;/p&gt;

&lt;p&gt;I also prefer to keep my content separate from the website’s design, and I wanted to do that without introducing a CMS or additional tooling. Static site generators like Jekyll are great at converting Markdown into websites, but they usually require you to store content alongside all the other website files.&lt;/p&gt;

&lt;p&gt;After some experimenting, I landed on a better solution: building a personal monorepo for my writing and publishing workflow.&lt;/p&gt;

&lt;h2 id=&quot;why-use-a-monorepo&quot;&gt;Why use a monorepo?&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;monorepo&lt;/em&gt;—short for monolithic repository—combines code for multiple projects into a single repository. A common pattern is to store both frontend and backend code in one place.&lt;/p&gt;

&lt;p&gt;That’s actually a good analogy for how I think about writing. The “backend” is my Obsidian vault, where I research and take notes. The “frontend” is the website where I publish finished posts.&lt;/p&gt;

&lt;h2 id=&quot;basic-setup&quot;&gt;Basic Setup&lt;/h2&gt;

&lt;p&gt;To start ,I moved my Obsidian vault and Jekyll website into a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;personal-monorepo&lt;/code&gt; directory structured like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~/personal-monorepo
├── /notes
└── /website
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you don’t already have an Obsidian vault or Jekyll site, you can easily replicate this from scratch. Install Obsidian, open the &lt;strong&gt;/notes&lt;/strong&gt; directory using the “Open folder as vault” option, and you’re ready to go.&lt;/p&gt;

&lt;p&gt;Setting up Jekyll requires a bit more technical work, but &lt;a href=&quot;https://jekyllrb.com/docs/installation/&quot;&gt;you can find installation instructions here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;configuring-obsidian&quot;&gt;Configuring Obsidian&lt;/h2&gt;

&lt;p&gt;For this approach it’s important to make a directory where you will only store published posts. I’m going to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/notes/posts&lt;/code&gt; for this tutorial but you can configure this directory any way you wish.&lt;/p&gt;

&lt;p&gt;I also recommend installing two Obsidian community plugins:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/Vinzent03/obsidian-git&quot;&gt;Obsidian Git&lt;/a&gt; – adds version control and makes publishing easy&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kepano/obsidian-permalink-opener&quot;&gt;Obsidian Permalink Opener&lt;/a&gt; – lets you open post URLs in your browser for previewing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Git, you can push commits manually or set up periodic syncs. For the Permalink Opener plugin, I added both my website’s base URL and my local development URL so I can preview posts in the browser while editing.&lt;/p&gt;

&lt;p&gt;With that we’re ready to move on to building our website.&lt;/p&gt;

&lt;h2 id=&quot;connecting-jekyll-and-obsidian&quot;&gt;Connecting Jekyll and Obsidian&lt;/h2&gt;

&lt;p&gt;By default, Jekyll looks for posts in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/website/_posts&lt;/code&gt;. But I want it to use the content in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/notes/posts&lt;/code&gt;. The simplest solution is to create a symbolic link.&lt;/p&gt;

&lt;p&gt;First, open Terminal and make sure you’re in the root of your monorepo (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/personal-monorepo&lt;/code&gt;). &lt;strong&gt;Back up your content&lt;/strong&gt;, then delete the existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-rf&lt;/span&gt; website/_posts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, create a symlink that points to your Obsidian posts:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;website
&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; ../notes/_posts _posts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Folder names in symlinks are case-sensitive. If your Obsidian vault uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Posts&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;posts&lt;/code&gt;, your symlink won’t work with the above command. Folder names must match exactly.&lt;/p&gt;

&lt;h2 id=&quot;publishing-with-netlify&quot;&gt;Publishing with Netlify&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt; provides first-class support for working with monorepos, but you’ll need to do a little additional configuration.&lt;/p&gt;

&lt;p&gt;In your project dashboard or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netlify.toml&lt;/code&gt; file, set the base directory to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;website&lt;/code&gt;, and make sure the build command installs dependencies before running Jekyll:&lt;/p&gt;

&lt;p&gt;Here’s what my full &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netlify.toml&lt;/code&gt; looks like, and what is reflected in my dashboard:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;base = &quot;website&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;command = &quot;bundle install &amp;amp;&amp;amp; bundle exec jekyll build&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;publish = &quot;_site&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Netlify follows symlinks automatically, but Jekyll needs one extra setting. In your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;website/_config.yml&lt;/code&gt;, add:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Enable access to symlinked content&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;lax_symlink_lookup&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This lets Jekyll access files stored outside its root directory (e.g. the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;website&lt;/code&gt; folder). Without the site will build but won’t pull in your content from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notes/_posts&lt;/code&gt; directory.&lt;/p&gt;

&lt;h2 id=&quot;final-workflow&quot;&gt;Final Workflow&lt;/h2&gt;

&lt;p&gt;I have Obsidian configured to add new notes to my writing inbox under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~inbox&lt;/code&gt; directory. Anything I start writing goes there. Once I’ve finished writing a note, I can then either move it into my permanent notes or add it to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;posts&lt;/code&gt; directory if I want to publish it. Once I push the commit Netlify will build and publish my site.&lt;/p&gt;

&lt;p&gt;While I’m writing, I can preview what the note will look like by starting the Jekyll development server (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle exec jekyll serve&lt;/code&gt;) and adding the note to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;posts&lt;/code&gt; directory. I can use the Obsidian hotlinks command to open a preview of the post in my browser.&lt;/p&gt;

&lt;p&gt;To wrap up, your final workflow looks something this this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Write, edit, and link notes in Obsidian&lt;/li&gt;
  &lt;li&gt;Commit and push changes to Github&lt;/li&gt;
  &lt;li&gt;Netlify will pick up the changes and publish your posts&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;bonus-convert-backlinks-to-weblinks&quot;&gt;Bonus: Convert Backlinks to Weblinks&lt;/h2&gt;

&lt;p&gt;It’s outside the scope of this post, but I also wrote a custom plugin to convert backlinks to web links. That way I can use Obsidian’s backlinks within my published posts.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/andrewstiefel/andrewstiefel.com/blob/main/_plugins/backlinks.rb&quot;&gt;You can grab the code here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://alexoliveira.cc/guide/jekyll-with-obsidian&quot;&gt;Jekyll Blogging with Obsidian&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://refinedmind.co/obsidian-jekyll-workflow&quot;&gt;Obsidian Jekyll workflow&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/adrianogil/blogging-with-obsidian-and-jekyll-5bgl&quot;&gt;Blogging with Obsidian and Jekyll&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stephango.com/vault&quot;&gt;How I Use Obsidian&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>AI isn't taking your job — the economy is</title>
   <link rel="alternate" href="https://andrewstiefel.com/ai-layoff-myth/"/>
   <published>2025-05-16T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/ai-layoff-myth</id>
   <summary>AI is the excuse, not the cause, behind layoffs across tech and beyond.</summary>
   <content type="html">&lt;p&gt;Have you noticed the latest trend sweeping executive suites? This year, layoff announcements are getting &lt;a href=&quot;https://sfstandard.com/2025/02/27/salesforce-marcbenioff-layoffs-tech-agents/&quot;&gt;blamed on AI&lt;/a&gt;. Or maybe it’s &lt;a href=&quot;https://www.usatoday.com/story/money/2025/02/10/meta-layoffs-2025/78383801007/&quot;&gt;employee performance&lt;/a&gt;. No — it’s &lt;a href=&quot;https://techcrunch.com/2025/05/15/programmers-bore-the-brunt-of-microsofts-layoffs-in-its-home-state-as-ai-writes-up-to-30-of-its-code/&quot;&gt;definitely AI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But if you look closer, you’ll find a more familiar culprit: the economy.&lt;/p&gt;

&lt;p&gt;Companies don’t want to admit revenue is slowing or that fundamentals are crumbling. It’s easier to say they’re “embracing AI” than to admit they’re under pressure to cut costs and protect margins.&lt;/p&gt;

&lt;p&gt;Yes, AI is changing how we work — especially for junior roles in software development, sales, content creation, and support. But the wave of layoffs sweeping tech, healthcare, and biotech isn’t being driven by machines replacing humans. It’s being driven by &lt;strong&gt;elevated interest rates, post-Covid revenue declines, and investor pressure to do more with less.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI just provides a convenient cover narrative.&lt;/p&gt;

&lt;h2 id=&quot;a-correction-disguised-as-innovation&quot;&gt;A Correction Disguised as Innovation&lt;/h2&gt;

&lt;p&gt;Several major tech firms — including cloud providers, social platforms, and enterprise software giants — have collectively laid off more than 600,000 workers since 2022 according to &lt;a href=&quot;https://layoffs.fyi/&quot;&gt;Layoffs.fyi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These cuts impacted recruiting, HR, operations, marketing, and in some cases engineering. Companies that ramped up quickly during the pandemic suddenly found they were overextended in a post-zero interest rate policy (ZIRP) world. Capital became more expensive. Growth expectations took a cut. And investors needed to see profitability instead.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;Covid-era bubble correcting itself&lt;/strong&gt;. Most of these companies are still larger than they were in 2019. In fact, as &lt;a href=&quot;https://newsletter.pragmaticengineer.com/p/software-engineering-job-openings&quot;&gt;research by the Pragmatic Engineer&lt;/a&gt; has shown, software engineering in particular has experienced a boom and bust.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The change in the number of listings in 2025, compared to 2020, for each of these areas:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;All jobs: +10%&lt;/li&gt;
    &lt;li&gt;Banking and finance: -7%&lt;/li&gt;
    &lt;li&gt;Sales: -8%&lt;/li&gt;
    &lt;li&gt;Marketing: -19%&lt;/li&gt;
    &lt;li&gt;Software development: -34%&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Overall hiring has mostly returned to 2019 levels. There is a hesitation to hire more, but that’s partially due to uncertainty about the level to hire for with AI and ongoing uncertainty about macroeconomic conditions.&lt;/p&gt;

&lt;h2 id=&quot;from-tech-to-biotech-the-narrative-spreads&quot;&gt;From Tech to Biotech: The Narrative Spreads&lt;/h2&gt;

&lt;p&gt;Like any good pathogen, narratives like to spread. And this one is jumping from Silicon Valley to biotech and healthcare – the other industries most impacted by Covid-19.&lt;/p&gt;

&lt;p&gt;A large mRNA vaccine manufacturer recently announced that it was merging the CTO and Head of People into a new Chief People and Digital Technology Officer role. The stated reason? &lt;a href=&quot;https://www.wsj.com/articles/why-moderna-merged-its-tech-and-hr-departments-95318c2a&quot;&gt;To identify which roles are best suited for AI vs people&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But they are following a now-familiar playbook:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The company &lt;a href=&quot;https://news.modernatx.com/news/news-details/2025/Moderna-Reports-First-Quarter-2025-Financial-Results-and-Provides-Business-Updates/default.aspx&quot;&gt;reported a GAAP net loss of $1.1 billion loss in Q1 2025&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Revenue from Covid-era mRNA vaccines continues to fall&lt;/li&gt;
  &lt;li&gt;They have reduced operating costs by 19% to compensate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Behind the scenes, it’s facing post-pandemic revenue decline and investor pressure to reduce costs. So they’re turning to layoffs — with AI as the smokescreen.&lt;/p&gt;

&lt;h2 id=&quot;so-what-is-ai-doing-to-jobs&quot;&gt;So what is AI doing to jobs?&lt;/h2&gt;

&lt;p&gt;There is no question AI is changing work. I use AI in my job nearly every day. And it’s definitely impacting the labor market. A &lt;a href=&quot;https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4945566&quot;&gt;recent study&lt;/a&gt; found that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Junior developers experienced 27-39% productivity gains using AI coding tools.&lt;/li&gt;
  &lt;li&gt;But senior developers saw smaller productivity gains, typically 8-13%.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI enhances speed, but doesn’t replace deep expertise yet. In fact, the more you know about a subject or field the less magical it is.&lt;/p&gt;

&lt;p&gt;Unsurprisingly, entry-level roles are the first to feel the effects: SEO writers, junior engineers, SDRs, and support teams. But the scale is smaller than the headlines suggest.&lt;/p&gt;

&lt;p&gt;Even firms that &lt;a href=&quot;https://www.businessinsider.com/klarna-ceo-sebastian-siemiatkowski-ai-jobs-2024-12&quot;&gt;proudly&lt;/a&gt; &lt;a href=&quot;https://edition.cnn.com/2024/01/09/tech/duolingo-layoffs-due-to-ai/index.html&quot;&gt;touted&lt;/a&gt; major AI-based role reductions have &lt;a href=&quot;https://www.entrepreneur.com/business-news/klarna-ceo-reverses-course-by-hiring-more-humans-not-ai/491396&quot;&gt;quietly reversed course&lt;/a&gt; — reopening hiring in those same departments just months later.&lt;/p&gt;

&lt;h2 id=&quot;the-bottom-line&quot;&gt;The Bottom Line&lt;/h2&gt;

&lt;p&gt;Companies aren’t laying people off because AI is replacing them. At least, not yet. If you’re familiar with AI technology, you know both how far and fast it has come — and all the countless ways it hallucinates or falls flat. It makes a great assistant, but a lousy replacement.&lt;/p&gt;

&lt;p&gt;So don’t mistake narrative spin for a technological inevitability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI isn’t coming for your job. Because the CFO already did.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; The views expressed in this post are my own and do not reflect the opinions or positions of my employer. Company examples have been anonymized to focus on trends rather than individual firms. All references are drawn from publicly reported data.&lt;/em&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How I use GitHub as a CMS</title>
   <link rel="alternate" href="https://andrewstiefel.com/github-cms-blog/"/>
   <published>2025-02-02T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/github-cms-blog</id>
   <summary>GitHub makes it easy to build a free content management system for your blog.</summary>
   <content type="html">&lt;p&gt;I use &lt;a href=&quot;/blog-jekyll-netlify/&quot; class=&quot;internal-link&quot; data-preview-title=&quot;How I built my blog with Jekyll and Netlify&quot; data-preview-excerpt=&quot;I’ve been blogging and hosting my website since 2006, but I’ve always been unhappy with the themes available for technologies like Blogger, WordPress, or Squarespace. I usually had a vision for what I wanted to create and would spend hours scouring marketplaces to find something that came close.&quot;&gt;Jekyll to build and publish my blog on Netlify&lt;/a&gt;. For a long time my content management system (CMS) was just a bunch of markdown files on my laptop. Most of the time I don’t need anything else — it’s simple, and it’s just me.&lt;/p&gt;

&lt;p&gt;But as I’ve wanted to focus on writing more often, I wanted to find an easier way to track future ideas, what I’d like to work on now, and easily see what I’ve done.&lt;/p&gt;

&lt;p&gt;That’s where GitHub comes in.&lt;/p&gt;

&lt;h2 id=&quot;why&quot;&gt;Why?&lt;/h2&gt;

&lt;p&gt;GitHub is built for software development, but many of the features work just as well for content development. In fact, is has about everything I need as you’ll see in my setup section below. This includes templates, project boards, and workflows for publishing.&lt;/p&gt;

&lt;p&gt;Plus it’s easy to review and collaborate with other people. I don’t do that much as a solo writer, but I do get readers who spot typos or who share feedback—and then it’s easy to track and add their contributions.&lt;/p&gt;

&lt;p&gt;But let’s be honest — this is one of the projects I took on because I could, not so much because it really saves me any time. Choose your adventure accordingly :)&lt;/p&gt;

&lt;h2 id=&quot;basic-setup&quot;&gt;Basic setup&lt;/h2&gt;

&lt;p&gt;If you’re already using GitHub to host the code for your blog (like I do with Jekyll), then you can get started with this in 15 minutes or less!&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Create a project:&lt;/strong&gt; Go to the GitHub repository for your blog (or make a new one!) and select projects and &lt;a href=&quot;https://docs.github.com/en/issues/planning-and-tracking-with-projects/creating-projects/creating-a-project&quot;&gt;create your project&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Choose a format:&lt;/strong&gt; GitHub projects lets you &lt;a href=&quot;https://docs.github.com/en/issues/planning-and-tracking-with-projects/customizing-views-in-your-project&quot;&gt;customize views&lt;/a&gt; of items in your project using a Kanban board or table format. I recommend starting with the Kanban format. You can always change this later.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Organize your workflow:&lt;/strong&gt; Once you’ve created your project, take a couple minutes to configure your workflow. I have sections for no status (my backlog), in progress, ready, and done.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can &lt;a href=&quot;https://github.com/users/andrewstiefel/projects/2&quot;&gt;see an example of mine on GitHub&lt;/a&gt;, or with the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/github-cms.png&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/github-cms.png&quot; alt=&quot;GitHub CMS&quot; width=&quot;2990&quot; height=&quot;1712&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;use-issues-to-track-posts&quot;&gt;Use issues to track posts&lt;/h2&gt;

&lt;p&gt;Once you’ve created the basic structure, it’s time to start tracking your writing! You’ll want to create new issues so you can track your progress. I decided to create a new template so I wouldn’t have to add the same info every time.&lt;/p&gt;

&lt;p&gt;If you’d like to create one, all you need to add is a markdown file in your repository at the location below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.
├── .github 
│   └── ISSUE_TEMPLATE
│      └── cms.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s &lt;a href=&quot;https://github.com/andrewstiefel/andrewstiefel.com/blob/main/.github/ISSUE_TEMPLATE/cms.md?plain=1&quot;&gt;an example&lt;/a&gt; of what mine looks like:&lt;/p&gt;

&lt;div class=&quot;language-markdown highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cms&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;about&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Submit an idea for the blog&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;[blog&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;post]&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cms&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;assignees&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

&lt;span class=&quot;gs&quot;&gt;**What is this post about?**&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;


&lt;/span&gt;&lt;span class=&quot;gs&quot;&gt;**Outline**&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;1.&lt;/span&gt; 

&lt;span class=&quot;gs&quot;&gt;**Tasks**&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; [ ] Write outline
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; [ ] Draft blog post
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; [ ] Find (1) reviewer
&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt; [ ] Create pull request
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use the format &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[blog post] example title&lt;/code&gt; so I can see at a glance that the issue covers a new blog post, and roughly what it’s about. I provide a brief description (usually when I first have the idea). Later I’ll come back and outline the post.&lt;/p&gt;

&lt;h2 id=&quot;writing-and-publishing-posts&quot;&gt;Writing and publishing posts&lt;/h2&gt;

&lt;p&gt;Jekyll comes with basic structure which makes it easy to get started. I save my draft writing in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_drafts&lt;/code&gt; folder and move finished posts into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; folder.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.
├── _drafts 
├── _posts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But you have a few options to customize your workflow a bit further:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Work directly in your main branch&lt;/strong&gt; and publish by moving the your finished drafts from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_drafts&lt;/code&gt; folder to the  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; folder.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Create a new branch&lt;/strong&gt; for each post as you work and merge into your main branch when you’re ready to publish.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;JEKYLL TIP&lt;/strong&gt; 
You can preview your posts in your development environment as you work! Just append the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&lt;/code&gt;drafts flag to the build or serve command. For example,  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll serve --drafts&lt;/code&gt;. Each draft post will be added using the last modified time as the publication date.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I prefer to create a new branch and to submit a pull request when I’m ready to publish (although I’ll admit, I’m not super consistent since it’s just me). Either way, when you’re ready to publish, you’ll &lt;a href=&quot;https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue&quot;&gt;close the issue&lt;/a&gt; for your blog by writing a commit message that includes the number of the issue. For example, when I published this blog, I used “Closes 212” to tell GitHub to mark the issue as done.&lt;/p&gt;

&lt;p&gt;Now if you visit your project, you’ll see your post has automatically been moved to the “done” column!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/github-pull-request.png&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/github-pull-request.png&quot; alt=&quot;GitHub Pull Request&quot; width=&quot;1166&quot; height=&quot;474&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;I’ve been exploring ways to &lt;a href=&quot;https://docs.github.com/en/issues/planning-and-tracking-with-projects/customizing-views-in-your-project&quot;&gt;customize this further by creating new views&lt;/a&gt; — for example, a table view that adds publication dates so I can when I want to publish a post. But most importantly, I’m enjoying the flexibility and close integration between what I write and how it’s published.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog-jekyll-netlify/&quot; class=&quot;internal-link&quot; data-preview-title=&quot;How I built my blog with Jekyll and Netlify&quot; data-preview-excerpt=&quot;I’ve been blogging and hosting my website since 2006, but I’ve always been unhappy with the themes available for technologies like Blogger, WordPress, or Squarespace. I usually had a vision for what I wanted to create and would spend hours scouring marketplaces to find something that came close.&quot;&gt;How I Built My Blog with Jekyll and Netlify&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/markdown-files-not-apps/&quot; class=&quot;internal-link&quot; data-preview-title=&quot;Markdown files, not apps&quot; data-preview-excerpt=&quot;Files, not apps. I&amp;#39;m convinced this is the best way to work in the future.\n\nI write down almost everything important in my life: lists, ideas, plans, code, and articles. They form my extended memory. They are a record of what I&amp;#39;ve done, and who I&amp;#39;ve been.&quot;&gt;Markdown Files, Not Apps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Markdown files, not apps</title>
   <link rel="alternate" href="https://andrewstiefel.com/markdown-files-not-apps/"/>
   <published>2025-01-17T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/markdown-files-not-apps</id>
   <summary>Markdown is simple, portable, and free. And it works beautifully with AI tools.</summary>
   <content type="html">&lt;p&gt;Files, not apps. I’m convinced this is the best way to work in the future.&lt;/p&gt;

&lt;p&gt;I write down almost everything important in my life: lists, ideas, plans, code, and articles. They form my extended memory. They are a record of what I’ve done, and who I’ve been. &lt;strong&gt;That’s why I only use markdown files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional document and note-taking apps like Word, Evernote, and Notion create data silos and vendor lock-in, limiting your ability to freely move and process information.&lt;/p&gt;

&lt;p&gt;I discovered this the hard way when I tried to move between different ecosystems like Evernote and Apple Notes. Sure, there was a way to export my data. But it was a mess. Things broke, attachments went missing, and I spent hours converting, reformatting, and importing.&lt;/p&gt;

&lt;h2 id=&quot;markdown-is-simple&quot;&gt;Markdown is simple&lt;/h2&gt;

&lt;p&gt;Markdown files solve these challenges through their fundamental simplicity. Any text editor can open and edit them, eliminating dependency on specific applications or platforms. They have all the basic formatting you need for headlines, bullets, lists, and even basic tables.&lt;/p&gt;

&lt;h2 id=&quot;markdown-is-portable&quot;&gt;Markdown is portable&lt;/h2&gt;

&lt;p&gt;If you use Evernote or Notion, for example, you are helpless without them. If they go out of business you are trapped and have to move your files to another format. &lt;strong&gt;You will outlive those companies.&lt;/strong&gt; I’ve already outlived a few note-taking companies.&lt;/p&gt;

&lt;p&gt;I can work with markdown files on any device, forever. I can access them with any text editor I want. This makes them remarkably long-lived. Proprietary formats come and go, but markdown’s open, plain text nature ensures it will likely outlast me. This makes it the ideal format for building a personal knowledge base.&lt;/p&gt;

&lt;h2 id=&quot;markdown-works-offline&quot;&gt;Markdown works offline&lt;/h2&gt;

&lt;p&gt;There are times when I want to be offline and unreachable, but would still like to jot ideas down in a format that is easily searchable. Working offline is an amazing productivity boost. Why give that up for an online database?&lt;/p&gt;

&lt;h2 id=&quot;markdown-is-ready-for-ai&quot;&gt;Markdown is ready for AI&lt;/h2&gt;

&lt;p&gt;This is a use case I wouldn’t have imagined a few years. But it’s the main reason I’m convinced markdown files are the future. Since markdown is just text, AI systems can easily process and analyze your notes.&lt;/p&gt;

&lt;p&gt;For example, I can easily grab my “Ideal Customer Profile.md” file and throw it into ChatGPT, Claude, Gemini, or whatever I’m using at the moment to work with it. I can add my messaging framework, and immediately start brainstorming marketing copy.&lt;/p&gt;

&lt;p&gt;I can run a local LLM, point it at a folder of my markdown files, and then interact with my notes by asking questions. It’s like a personal assistant built on everything I’ve learned and experienced.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Everything I write is human readable, and yet actionable with apps and tools. I always have my files available locally, and backups are just making a copy of the folder and putting it somewhere safe.&lt;/p&gt;

&lt;p&gt;Markdown is simple, portable, independent, and free — exactly how I want to live.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Principles of platform independence</title>
   <link rel="alternate" href="https://andrewstiefel.com/principles-platform-independence/"/>
   <published>2025-01-10T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/principles-platform-independence</id>
   <summary>A short guide to choosing apps and services that preserve your digital freedom by avoiding ecosystem lock-in.</summary>
   <content type="html">&lt;p&gt;The internet is filled with stories of people breaking free from Google’s ecosystem (&lt;a href=&quot;https://coryd.dev/posts/2014/leaving-google-apps-for-fastmail&quot;&gt;here&lt;/a&gt; &lt;a href=&quot;https://www.nytimes.com/2024/04/07/opinion/gmail-email-digital-shame.html&quot;&gt;are&lt;/a&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=YnSv8ylLfPw&quot;&gt;a&lt;/a&gt; &lt;a href=&quot;https://guissmo.com/blog/degoogling-2024-alternatives-to-google-that-i-am-using/&quot;&gt;few&lt;/a&gt; &lt;a href=&quot;https://news.ycombinator.com/item?id=39882468&quot;&gt;examples&lt;/a&gt; I’ve seen recently). Yet in their rush to escape one tech giant, many users inadvertently chain themselves to another.&lt;/p&gt;

&lt;p&gt;I’ve noticed a paradox on social media: people who champion digital independence while relying heavily on platform-specific tools like Apple Notes or Passwords. They overlook how Apple, like Google, builds its business model around service lock-in – from iCloud storage to annual hardware upgrades.&lt;/p&gt;

&lt;p&gt;Personally, I prefer to maintain platform independence as much as possible. Over the years I’ve developed a set of criteria — let’s call them principles of platform independence — for choosing what apps and software I use. This way I retain control over my digital life regardless of which company’s software or hardware I use.&lt;/p&gt;

&lt;h2 id=&quot;1-cross-platform-compatibility&quot;&gt;1) Cross-Platform Compatibility&lt;/h2&gt;
&lt;p&gt;Use applications that work across different operating systems (MacOS, Windows, Linux, etc.) to avoid being locked into one platform’s ecosystem. This ensures your workflow remains consistent regardless of the device you’re using.&lt;/p&gt;

&lt;h2 id=&quot;2-data-ownership&quot;&gt;2) Data Ownership&lt;/h2&gt;
&lt;p&gt;Choose applications that allow you to easily export your data in formats that can be read by different applications. You should have full control of your data, and it should be accessible in a readable format outside of the application.&lt;/p&gt;

&lt;h2 id=&quot;3-data-portability&quot;&gt;3) Data Portability&lt;/h2&gt;
&lt;p&gt;Beyond just being able to export data, it should be in widely-supported open formats (like CalDAV for calendars, IMAP for email) rather than proprietary ones. This enables interoperability and switching between different clients.&lt;/p&gt;

&lt;h2 id=&quot;4-logic-separation&quot;&gt;4) Logic Separation&lt;/h2&gt;
&lt;p&gt;Your data shouldn’t be tightly coupled to specific application features. For example, your notes should be stored in a format that preserves basic formatting even if specific application features aren’t available elsewhere.&lt;/p&gt;

&lt;h2 id=&quot;5-local-control&quot;&gt;5) Local Control&lt;/h2&gt;
&lt;p&gt;Whenever possible, you should have direct access to your data in a readable format on your local system, not just through a cloud interface. This includes the ability to make local backups. I like to keep a version in the cloud, a version on my local system, a local backup, and a remote back up.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Dead internet is no longer a theory</title>
   <link rel="alternate" href="https://andrewstiefel.com/dead-internet-theory-real/"/>
   <published>2025-01-03T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/dead-internet-theory-real</id>
   <summary>Meta steps through the black mirror with the launch of AI user profiles.</summary>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Dead_Internet_theory&quot;&gt;Dead internet theory&lt;/a&gt; suggests most of the internet’s content and traffic is artificially generated by bots rather than humans. The conspiracy theory emerged amidst the fallout of the 2016 election, when news broke about websites creating fake news to gain clicks on Facebook and Google and leveraging bot accounts to amplify it.&lt;/p&gt;

&lt;p&gt;Ironically, Meta decided to turn the conspiracy theory into reality.&lt;/p&gt;

&lt;h2 id=&quot;meta-looks-into-the-black-mirror&quot;&gt;Meta looks into the black mirror&lt;/h2&gt;

&lt;p&gt;Quoting from &lt;a href=&quot;https://www.404media.co/metas-ai-profiles-are-indistinguishable-from-terrible-spam-that-took-over-facebook/&quot;&gt;404 Media&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Earlier this week, Meta executive Connor Hayes told the &lt;em&gt;Financial Times&lt;/em&gt; that the company is going to roll out AI character profiles on Instagram and Facebook that “exist on our platforms, kind of in the same way that accounts do … they’ll have bios and profile pictures and be able to generate and share content powered by AI on the platform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It didn’t take long for users on &lt;a href=&quot;https://bsky.app/profile/jasonkoebler.bsky.social/post/3leu3l7fcas22&quot;&gt;Blue Sky&lt;/a&gt; and &lt;a href=&quot;https://www.reddit.com/r/mildlyinfuriating/comments/1hsqe2z/metas_aigenerated_profiles_are_starting_to_show/?rdt=62372&quot;&gt;Reddit&lt;/a&gt; to find some of these fake AI profiles on Instagram. The profiles were often offensive caricatures of what a gigantic corporation like Meta might imagine a “proud Black queer momma of 2” might post about. The profiles tended to post AI generated content similar to what other spammer’s on Meta’s Facebook and Instagram platforms have been creating.&lt;/p&gt;

&lt;p&gt;Here’s the example I referenced above:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/metas-ai-generated-profiles-are-starting-to-show-up.webp&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/metas-ai-generated-profiles-are-starting-to-show-up.webp&quot; alt=&quot;Meta AI Generated Profile&quot; width=&quot;1205&quot; height=&quot;1743&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Most of these profiles were already a few years old, and Meta has since announced that they will be taking them down.&lt;/p&gt;

&lt;p&gt;Dead internet theory gained traction online because it speaks to genuine concerns people have about authenticity and the increasing use of bots and AI online. I have no idea how anyone at Meta could think launching this exact thing would be a good idea.&lt;/p&gt;

&lt;p&gt;I also suspect these profiles will still get rolled out in the future. But next time they won’t have the “AI managed by Meta” labels attached to them.&lt;/p&gt;

&lt;h2 id=&quot;navigating-the-dark-forest&quot;&gt;Navigating the dark forest&lt;/h2&gt;

&lt;p&gt;So where to from here? We’re entering &lt;a href=&quot;https://ystrickler.medium.com/the-dark-forest-theory-of-the-internet-7dc3e68a7cb1&quot;&gt;a new dark forest&lt;/a&gt; where it’s increasingly difficult to find the humans among the trees. Maggie Appleton tackled these challenges in one of her blog post’s entitled “&lt;a href=&quot;https://maggieappleton.com/ai-dark-forest&quot;&gt;The Dark Forest and Generative AI&lt;/a&gt;.”&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Humans who want to engage in informal, unoptimized, personal interactions have to hide in closed spaces like invite-only Slack channels, Discord groups, email newsletters, small-scale blogs, and &lt;a href=&quot;https://maggieappleton.com/garden-history&quot;&gt;digital gardens&lt;/a&gt;  . Or make themselves &lt;a href=&quot;https://www.ribbonfarm.com/2010/07/26/a-big-little-idea-called-legibility/&quot;&gt;illegible&lt;/a&gt;  and algorithmically incoherent in public venues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The new challenge isn’t generating content — it’s proving that you’re human.&lt;/p&gt;

&lt;p&gt;Fortunately, we humans evolved a whole bag of tricks to tell if something is a predator or not in the forest. Now we have to apply them online. Appleton suggests a few techniques in her post:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Triangulate – verify information from multiple sources (e.g. the &lt;a href=&quot;https://www.bbc.com/future/article/20240509-the-sift-strategy-a-four-step-method-for-spotting-misinformation&quot;&gt;SIFT strategy&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Be original – introduce new ideas (AI can only share what’s come before)&lt;/li&gt;
  &lt;li&gt;Be creative – use language quirks that AI wouldn’t use&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the future I expect we’ll see more institutional verification, similar to what LinkedIn has been rolling out for profiles. In LinkedIn’s case they are using a mix of ID verification (drivers license, passport, etc) to verify people and email verification to confirm companies.&lt;/p&gt;

&lt;h2 id=&quot;back-to-irl-as-the-norm&quot;&gt;Back to IRL as the norm?&lt;/h2&gt;

&lt;p&gt;If there’s something to be optimistic about, I suspect it will be the re-emergence of in-person value. Before the pandemic we were already seeing an uptick in “digital essentialism” as people got tired. We were then thrown even more into the online realm with the pandemic, and now we’re seeing more and more &lt;a href=&quot;https://www.nytimes.com/2024/09/24/us/politics/haitian-migrants-disinformation.html&quot;&gt;misinformation&lt;/a&gt;, &lt;a href=&quot;https://www.fastcompany.com/91192544/whats-astroturfing-the-deceptive-campaign-strategy-explained&quot;&gt;astroturfing&lt;/a&gt;, and other deceptive practices online. I suspect more and more of us will be looking for connection outside the old electronic waterholes of Facebook, Instagram, etc.&lt;/p&gt;

&lt;p&gt;I, personally, look forward to a slower, less online world if that’s indeed the future.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>The myth of the average user</title>
   <link rel="alternate" href="https://andrewstiefel.com/myth-average-user/"/>
   <published>2024-12-31T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/myth-average-user</id>
   <summary>A 1940s Air Force crisis revealed a crucial design principle — the average user doesn't exist.</summary>
   <content type="html">&lt;p&gt;This particular bit of history will live forever in my head.&lt;/p&gt;

&lt;p&gt;In the late 1940s, the U.S. Air Force faced a deadly crisis: their pilots were crashing at an alarming rate, with 17 crashes in a single day at its peak. The military knew something was terribly wrong, but the cause eluded them.&lt;/p&gt;

&lt;p&gt;Enter Lieutenant Gilbert Daniels, who conducted a groundbreaking study of 4,063 pilots. His discovery was shocking: when measuring ten critical body dimensions used for cockpit design, not a single pilot fell within the average range across all measurements. Not one.&lt;/p&gt;

&lt;p&gt;This is the “flaw of averages” – the mathematical reality that designing for the average means designing for no one. The average user, like the average pilot, is a statistical ghost.&lt;/p&gt;

&lt;p&gt;The Air Force’s solution revolutionized aviation: they abandoned the myth of the average pilot and instead created adjustable equipment. Cockpits with customizable seats, moveable control panels, and adaptable displays became the new standard – a design philosophy that saved countless lives.&lt;/p&gt;

&lt;p&gt;This lesson extends far beyond aviation. While I always knew that averages could be misleading (after all, a single outlier can dramatically skew results), I never realized just how fundamentally flawed the concept of “average” could be.&lt;/p&gt;

&lt;p&gt;The truth is simple: none of your users are average. Each person who interacts with your product brings their own unique needs, preferences, and ways of working. The key to exceptional design isn’t creating the perfect solution for an imaginary average user – it’s building flexibility into your core experience.&lt;/p&gt;

&lt;p&gt;When designing software, you can (and should) have strong opinions about optimal workflows. But you should also embrace edge cases – whether it’s the power user who needs advanced features or the newcomer who needs a simplified interface – to create solutions that work for everyone.&lt;/p&gt;

&lt;p&gt;Want to dive deeper into this fascinating story? &lt;a href=&quot;https://www.thestar.com/news/insight/when-u-s-air-force-discovered-the-flaw-of-averages/article_e3231734-e5da-5bf5-9496-a34e52d60bd9.html&quot;&gt;Check out the original article in the Toronto Star for more details&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Weighing in on AI hype and risk</title>
   <link rel="alternate" href="https://andrewstiefel.com/ai-hype-risk/"/>
   <published>2024-12-10T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/ai-hype-risk</id>
   <summary>There’s been a fight over the past few days about Casey Newton's article. Here's my take.</summary>
   <content type="html">&lt;p&gt;Casey Newton wrote a piece last Thursday titled “&lt;a href=&quot;https://www.platformer.news/ai-skeptics-gary-marcus-curve-conference/&quot;&gt;The phony comforts of AI skepticism&lt;/a&gt;” — and wow did people have some thoughts about it:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gary Marcus &lt;a href=&quot;https://garymarcus.substack.com/p/hard-forked-casey-newtons-distorted&quot;&gt;responded against the mischaracterization of his position&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Edward Ongweso &lt;a href=&quot;https://thetechbubble.substack.com/p/the-phony-comforts-of-useful-idiots?&quot;&gt;had quite a few more things to say&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Casey Newton &lt;a href=&quot;https://www.platformer.news/ai-fake-and-sucks-revisited/&quot;&gt;responded&lt;/a&gt; while basically doubling down on his argument&lt;/li&gt;
  &lt;li&gt;Dave Karpf &lt;a href=&quot;https://davekarpf.substack.com/p/weighing-in-on-casey-newtons-ai-is&quot;&gt;waded in with his perspective&lt;/a&gt; and a recap of the debate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m sure there’s more out there but you get the idea. I almost didn’t write something myself, but one part of this conversation still feels like it’s missing to me. So let’s take a brief look at Newton’s argument before diving in.&lt;/p&gt;

&lt;h2 id=&quot;newtons-argument-in-a-nutshell&quot;&gt;Newton’s argument in a nutshell&lt;/h2&gt;

&lt;p&gt;To briefly summarize, the core thrust of Newton’s piece is that the entire range of AI discussion boils down to two groups: critics external to firms and organizations directly working on or studying AI who believe “AI is fake and sucks” and internal critics building AI who understand “AI is real and dangerous” given current and future capabilities. 
Newton aligns himself with the latter and suggests that the former camp are not only incapable of recognizing genuine innovations made in this field, but risk leaving us blind to threats enabled by those advances.&lt;/p&gt;

&lt;p&gt;It’s a widely reductive argument and Marcus and Ongweso do a great job of breaking down the issues with it, and in particular the straw man Newton builds for himself to attack. I’m not going to wade in there, but I recommend reading their posts for context.&lt;/p&gt;

&lt;p&gt;I want to talk about how smart journalists like Newton can accidentally (or intentionally) fall for the hype, and in the process fail to correctly frame the conversation for their readers. And I want to be clear up front: I think this was a huge miss.&lt;/p&gt;

&lt;h2 id=&quot;a-false-dichotomy&quot;&gt;A false dichotomy&lt;/h2&gt;

&lt;p&gt;My particular issue with Newton’s article is about the placement of what I’ll call skepticism (“AI is fake and sucks”) and hype (“AI is real and dangerous”) as polar opposites on a spectrum. It’s so wildly off I’m surprised Newton chose to defend it. As many people noted in comments on Mastodon and Bluesky, the skeptics Newton is attacking are more likely to fall into the “AI is real and dangerous &lt;em&gt;and is also&lt;/em&gt; fake and sucks” category.&lt;/p&gt;

&lt;p&gt;Understanding how current generative AI models, and large language models (LLMs) in particular, fail to deliver on their promise usually means you also understand how dangerous these models are now, and will be in the future. Those shortcomings are especially dangerous when they are released to a public that doesn’t understand what those shortcomings are, and into a media environment that is still grappling with the ramifications of social media.&lt;/p&gt;

&lt;h2 id=&quot;sorting-out-risk-from-hype&quot;&gt;Sorting out risk from hype&lt;/h2&gt;

&lt;p&gt;My bigger issue is that Newton seems to fall for the hype from the people building and most likely to benefit from advances in AI. And make no mistake, making unsubstantiated claims about the future dangers of AI is a way of creating hype around the technology. It’s probably the oldest form of hype in computer science – we’ve been talking about imagined AI risks since at least the &lt;a href=&quot;https://en.wikipedia.org/wiki/Darwin_among_the_Machines&quot;&gt;mid-19th century&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem here is that hypothetical risks are treated the same as actual risks. We know that the current GenAI models are accelerants to the issues of propaganda and misinformation that were already widely present on social media and other communication channels before ChatGPT was released. GenAI models are also wrong quite often, despite attempts to improve them, leading to a new form of misinformation when users aren’t appropriately skeptical of the responses they receive. And that doesn’t get into whether LLMs are even a viable path to true general intelligence or not.&lt;/p&gt;

&lt;p&gt;We should be talking about emerging risks, but we need a lot more grounding in the conversation from journalists like Newton. And we should differentiate these as hypothetical risks, and they should be treated with more skepticism, &lt;a href=&quot;https://ali-alkhatib.com/blog/defining-ai&quot;&gt;especially when they come from the people most likely to benefit from them&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;As Marcus outlines at the start his essay, Newton does get a lot right, including that we should be preparing now for AI to get more dangerous. And we should be documenting the different attitudes that are emerging around AI. I agree with all this.&lt;/p&gt;

&lt;p&gt;But we need the media to do a better job of framing the emerging discussion and attitudes towards AI &lt;em&gt;without&lt;/em&gt; serving as hype for the individuals and firms building and benefitting from these models.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How to package new product features</title>
   <link rel="alternate" href="https://andrewstiefel.com/pricing-packaging-innovation/"/>
   <published>2024-10-19T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/pricing-packaging-innovation</id>
   <summary>This framework can help you decide how to package new product innovations based on customer needs and perceived value.</summary>
   <content type="html">&lt;p&gt;When your company develops new innovations, a key question is: how should you package those features within your current product tiers? This decision can significantly impact customer perception of value and the ease of selling it.&lt;/p&gt;

&lt;p&gt;There are two main factors to consider:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Perceived value&lt;/strong&gt; – How much will customers see this innovation as something that enhances their experience or solves a problem?&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Target customer size&lt;/strong&gt; – How many of your customers would actually benefit from it?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s an easy framework to visualize your options:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/Packaging-Innovation-Framework.png&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/Packaging-Innovation-Framework.png&quot; alt=&quot;How to package innovation&quot; width=&quot;1583&quot; height=&quot;1477&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;1-new-product-or-tier&quot;&gt;1. New Product or Tier&lt;/h3&gt;
&lt;p&gt;If the new capability stretches beyond the value of your existing tiers, or it could shift the positioning of your entire product, it may be better to create a new tier or even an entirely new product. This will need more effort in field enablement and communication, but it also opens the door to greater potential revenue.&lt;/p&gt;

&lt;h3 id=&quot;2-add-it-to-an-existing-tier&quot;&gt;2. Add it to an Existing Tier&lt;/h3&gt;
&lt;p&gt;This is the right call if the innovation fits seamlessly with the current messaging of your product. Adding it to an existing tier can make the sales process easier because you’re building on something customers already understand.&lt;/p&gt;

&lt;h3 id=&quot;3-make-it-an-add-on&quot;&gt;3. Make it an Add-on&lt;/h3&gt;
&lt;p&gt;Sometimes, the innovation only appeals to a small segment of your customer base. In this case, packaging it as an add-on is a good move. This way, it doesn’t disrupt your core product offering, but customers who need that extra functionality can still get it.&lt;/p&gt;

&lt;h3 id=&quot;4-do-nothingkill-the-initiative&quot;&gt;4. Do Nothing/Kill the Initiative&lt;/h3&gt;
&lt;p&gt;And sometimes, the best option is to not move forward at all. If the perceived value is low and only a small percentage of your customers would care about it, it might be better to shelve the idea and try something else.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Working with multiple GitHub accounts and SSH keys</title>
   <link rel="alternate" href="https://andrewstiefel.com/working-multiple-github-accounts/"/>
   <published>2024-05-09T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/working-multiple-github-accounts</id>
   <summary>Learn how to use 1Password to sign Git commits for multiple GitHub accounts on one machine</summary>
   <content type="html">&lt;p&gt;I have multiple GitHub accounts – one for work, one for demos, and one for personal projects. Each has a unique email address, password, and 2FA associated with it. They also each have a unique SSH key. In fact, the SSH keys are all saved in different 1Password accounts (personal, demo, and work).&lt;/p&gt;

&lt;p&gt;In some cases I perform the development on the same device, like when I’m building a demo on my work device. In that case I need to make sure that I’m using the correct GitHub account and SSH key.&lt;/p&gt;

&lt;p&gt;I use 1Password as my &lt;a href=&quot;https://developer.1password.com/docs/ssh&quot;&gt;SSH agent&lt;/a&gt; because it keeps the private keys off my device, plus it makes authorizing SSH connections a breeze. I can authenticate a connection using Touch ID, so just a fingerprint touch on my keyboard and then I’m off to my next task.&lt;/p&gt;

&lt;p&gt;Fortunately, this only takes a few minutes to setup!&lt;/p&gt;

&lt;h2 id=&quot;organize-your-local-directory&quot;&gt;Organize your local directory&lt;/h2&gt;

&lt;p&gt;All my repositories are saved under a GitHub folder and then I use directories to organize my projects by account. Although I prefer to keep personal and work separate, you could configure all three accounts for a single device like in the example below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~/github
├── /demo
├── /personal
└── /work
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will make it very easy to configure which profile and SSH key to use in the following steps.&lt;/p&gt;

&lt;h2 id=&quot;set-your-global-gitconfig-file&quot;&gt;Set your global gitconfig file&lt;/h2&gt;

&lt;p&gt;In this example, I’m setting my personal Git configuration as the global default. Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[includeIf]&lt;/code&gt; I specify a different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitconfig&lt;/code&gt; file for the &lt;strong&gt;demo &lt;/strong&gt;and &lt;strong&gt;work &lt;/strong&gt;directories.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;user]
  name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &amp;lt;github_personal_name&amp;gt;
  email &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &amp;lt;github_personal_email&amp;gt;
  signingkey &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &amp;lt;your_ssh_key&amp;gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;gpg]
  format &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ssh

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;gpg &lt;span class=&quot;s2&quot;&gt;&quot;ssh&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  program &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/Applications/1Password.app/Contents/MacOS/op-ssh-sign&quot;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;commit]
  gpgsign &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;includeIf &lt;span class=&quot;s2&quot;&gt;&quot;gitdir:~/github/demo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  path &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ~/github/demo/.gitconfig

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;includeIf &lt;span class=&quot;s2&quot;&gt;&quot;gitdir:~/github/work&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  path &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ~/github/work/.gitconfig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;create-gitconfig-files-for-each-directory&quot;&gt;Create gitconfig files for each directory&lt;/h2&gt;

&lt;p&gt;Next I’ll create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitconfig&lt;/code&gt; files and save them in the &lt;strong&gt;demo &lt;/strong&gt;and &lt;strong&gt;work &lt;/strong&gt;directories. I’ll use a similar template, but this time I’ll provide the GitHub name, email, and public signing key for my demo and work accounts.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;user]
  name &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &amp;lt;github_work_name&amp;gt;
  email &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &amp;lt;github_work_email&amp;gt;
  signingkey &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &amp;lt;your_ssh_key&amp;gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;gpg]
  format &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; ssh

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;gpg &lt;span class=&quot;s2&quot;&gt;&quot;ssh&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  program &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/Applications/1Password.app/Contents/MacOS/op-ssh-sign&quot;&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;commit]
  gpgsign &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;configure-the-ssh-agent&quot;&gt;Configure the SSH agent&lt;/h2&gt;

&lt;p&gt;In order to call the correct SSH keys, I’ll need to update the SSH agent config file located at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I start by setting the 1Password SSH agent as the default for all hosts. Then I create custom hosts for each account, in this case&lt;strong&gt; Demo&lt;/strong&gt;,&lt;strong&gt; Personal&lt;/strong&gt;, and&lt;strong&gt; Work&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next, I downloaded the public keys from 1Password for my demo, personal, and work accounts. I renamed each file (for example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;demo_git.pub&lt;/code&gt;) and saved the all to my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/&lt;/code&gt; folder.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# By default, use the 1Password SSH agent for all hosts&lt;/span&gt;
Host &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
  IdentityAgent &lt;span class=&quot;s2&quot;&gt;&quot;~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Demo GitHub&lt;/span&gt;
Host gh-demo
    HostName github.com
    User git
    IdentityFile ~/.ssh/demo_git.pub
    IdentitiesOnly &lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Personal GitHub&lt;/span&gt;
Host gh-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/personal_git.pub
    IdentitiesOnly &lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Work GitHub&lt;/span&gt;
Host gh-work
    HostName github.com
    User git
    IdentityFile ~/.ssh/work_git.pub
    IdentitiesOnly &lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;reset-your-local-repositories&quot;&gt;Reset your local repositories&lt;/h2&gt;

&lt;p&gt;Finally, I’ll need to reset each individual repository so it uses one of the hosts specified above. This will make sure it uses the correct SSH key to authenticate with GitHub and when pushing Git commits.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git remote set-url origin &amp;lt;host&amp;gt;:&amp;lt;organization&amp;gt;/&amp;lt;repository&amp;gt;.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git remote -v&lt;/code&gt; to confirm that Git is using the correct remote repository. You can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fetch&lt;/code&gt; to confirm that 1Password offers up the correct SSH key for authentication.&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.1password.com/docs/ssh/git-commit-signing#configure-multiple-commit-signing-setups&quot; title=&quot;Configure Multiple Git Commit Signing Setups&quot;&gt;Configure Multiple Git Signing Setups&lt;/a&gt; (1Password)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.1password.com/docs/ssh/agent/advanced#use-multiple-github-accounts&quot; title=&quot;Use Multiple GitHub Accounts&quot;&gt;Use Multiple GitHub Accounts&lt;/a&gt; (1Password)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account&quot; title=&quot;Adding a New SSH Key to Your GitHub Account&quot;&gt;Adding a New SSH Key to Your GitHub Account&lt;/a&gt; (GitHub)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.1password.com/docs/ssh/git-commit-signing#step-2-register-your-public-key&quot; title=&quot;Register a Public SSH Key with GitHub&quot;&gt;Register a Public SSH Key with GitHub&lt;/a&gt; (1Password)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection&quot; title=&quot;Testing Your SSH Connection&quot;&gt;Testing Your SSH Connection&lt;/a&gt; (GitHub)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/authentication/troubleshooting-ssh/error-permission-denied-publickey#verify-the-public-key-is-attached-to-your-account&quot; title=&quot;Switching Remote URLs from HTTPS to SSH&quot;&gt;Switching Remote URLs from HTTPS to SSH&lt;/a&gt; (GitHub)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.to/sisco/optimize-your-git-setup-strategies-for-handling-multiple-github-accounts-3ji8&quot; title=&quot;Optimize Your Git Setup&quot;&gt;Optimize Your Git Setup: Strategies for Handling Multiple GitHub Accounts&lt;/a&gt; (Dev.to)&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Thoughts on information fidelity and transmission</title>
   <link rel="alternate" href="https://andrewstiefel.com/information-fidelity-transmission/"/>
   <published>2023-08-25T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/information-fidelity-transmission</id>
   <summary>Rich, complex ideas can have more impact — but they won't travel as far as a simple idea.</summary>
   <content type="html">&lt;p&gt;There is a useful axiom to keep in mind whenever you are crafting a message for someone else, whether writing a book, filming a video, or drafting an email.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Simple ideas travel farther than complex ones&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most of us intuitively understand this. But sometimes we forget as we get into the details of whatever we are doing. That’s why I like to keep the idea of fidelity vs transmission in mind.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/Information-Transmission-Fidelity-Dark-Mode-Revised.png&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/Information-Transmission-Fidelity-Dark-Mode-Revised.png&quot; alt=&quot;Information transmission and fidelity&quot; width=&quot;2366&quot; height=&quot;1158&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A book has hi-fidelity, but low transmission. You can read an author’s ideas in depth. Everything they wanted to tell you is there. But the full message — the text of the entire book itself — will practically never be remembered or transmitted, in detail, to the recipient. They may highlight the text, take notes, and summarize the text. But the full message will be lost.&lt;/p&gt;

&lt;p&gt;In contrast, a social media post has lo-fidelity, but high transmission. The full idea is almost invariably reduced to its essential elements. Details are left out. Things become black and white. But the recipient might be able to remember the entire message, so it has high transmission.&lt;/p&gt;

&lt;p&gt;This is why slogans are so powerful. They are easy to remember, and collect associations with other information you might have received or interacted with about a brand, politician, or idea. But they don’t have to communicate the whole thing – the recipient fills in the rest.&lt;/p&gt;

&lt;h2 id=&quot;why-does-this-matter&quot;&gt;Why does this matter?&lt;/h2&gt;

&lt;p&gt;There is an inherent tension between fidelity and transmission in all communication. Too much information, and your audience won’t remember what you needed them to know. Too little, and the message becomes banal, or simply worthless.&lt;/p&gt;

&lt;p&gt;There is an ethical element to navigate as well, especially when reporting or documenting someone else’s experience. Storytelling is reductive: it removes and flattens details in favor of creating an understandable narrative. The details you include or leave out will shape an audience’s understanding of the message you are communicating.&lt;/p&gt;

&lt;h2 id=&quot;what-does-this-look-like-in-practice&quot;&gt;What does this look like in practice?&lt;/h2&gt;

&lt;p&gt;Practically, this is why most messaging frameworks provide multiple tiers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Pillars&lt;/strong&gt; — Simple, two or three word phrases&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Key Message&lt;/strong&gt; — Short, memorable statements&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Proof Points&lt;/strong&gt; — supporting statements, benefits, or other evidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From here, you can expand into even higher fidelity forms like blog, videos, white papers, or books that expand and build on the summary provided by the messaging framework.&lt;/p&gt;

&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing Thoughts&lt;/h2&gt;

&lt;p&gt;We see the impact of this all the time. Stories go viral based on a bit of sensational news. But as the details come out, the original story turns out to be false. Bias and hate travels farther and faster than the nuance of compromise and collaboration.&lt;/p&gt;

&lt;p&gt;As a writer, marketer, or anyone who works with words, how do you balance fidelity and transmission in your work?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Writing for technical audiences</title>
   <link rel="alternate" href="https://andrewstiefel.com/writing-technical-audiences/"/>
   <published>2023-05-06T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/writing-technical-audiences</id>
   <summary>These tips can help you write more effectively for software developers, scientists, and other expert audiences.</summary>
   <content type="html">&lt;p&gt;Whether you are marketing to software developers, scientists, academic audiences, or other specialized industries, writing is a tool that can serve you well.&lt;/p&gt;

&lt;p&gt;But writing for technical audiences is a unique skill that requires a different set of techniques than copywriting for a consumer marketing campaign. You need not only an in-depth understanding of the subject but also the ability to convey complex information clearly and concisely.&lt;/p&gt;

&lt;p&gt;The following tips can help you to communicate your ideas more effectively.&lt;/p&gt;

&lt;h2 id=&quot;know-your-audience&quot;&gt;Know your audience&lt;/h2&gt;

&lt;p&gt;One of the tricky aspects of writing for technical audiences is knowing when to simplify something, and when to assume a level of advanced knowledge. Nothing drives developers, scientists, and other technical audiences away faster than overly simplified, 101-level writing. Occasionally, you do need 101-level content! But know what level of information your audience should already know.&lt;/p&gt;

&lt;p&gt;For example, I often write about API technologies. In 101-level content, I might define that the acronym API stands for an application programming interface. But if I start an article for a technical audience by introducing “what is an API” and defining the acronym, they are likely to quit reading and look for a resource that is more aligned with their knowledge level.&lt;/p&gt;

&lt;h2 id=&quot;use-clear-language&quot;&gt;Use clear language&lt;/h2&gt;

&lt;p&gt;When writing technical documents, it can be tempting to use complex technical jargon and terminology. However, this can often make your writing more difficult to understand, especially for those who are not familiar with the subject.&lt;/p&gt;

&lt;p&gt;To avoid confusion, it is best to use simple, clear language that is easy to understand. This means avoiding overly technical terms and breaking down complex concepts into more digestible pieces. You should also summarize key ideas in bullet points, which can help reinforce your ideas and improve retention.&lt;/p&gt;

&lt;p&gt;One of the most important first lessons I learned was to avoid adverbs whenever possible, especially in headlines. Adverbs typically make writing “feel like marketing” because they make broad claims (for example, “quickly, effortlessly, rapidly, always”).&lt;/p&gt;

&lt;h2 id=&quot;provide-evidence&quot;&gt;Provide evidence&lt;/h2&gt;

&lt;p&gt;In technical writing, you should avoid making sweeping statements or generalizations. It is important to back up any claims you make with evidence. This could be in the form of data, statistics, or references to existing research. By providing evidence to support your arguments, you can add credibility to your writing and show that your ideas are based on solid research and analysis.&lt;/p&gt;

&lt;p&gt;A brief word of caution: most technical audiences know what is a valuable resource, and what is marketing evidence. Use authoritative sources whenever possible, or commission relatively neutral third parties to conduct research on your behalf.&lt;/p&gt;

&lt;h2 id=&quot;give-concrete-examples&quot;&gt;Give concrete examples&lt;/h2&gt;

&lt;p&gt;Whenever possible, show rather than tell your audience how your product works. It’s one thing to claim that something is easier. But it’s more impactful to show it in action. Rather than relying on abstract concepts or hypothetical scenarios, try to use real-world examples to illustrate your points. For example, if you are writing a user manual for a software application, you could include screenshots or step-by-step instructions to help users understand how to use the software.&lt;/p&gt;

&lt;h2 id=&quot;use-visuals&quot;&gt;Use visuals&lt;/h2&gt;

&lt;p&gt;Visual aids can be extremely helpful in technical writing, as they can help to clarify complex concepts and make your writing more engaging. This could include diagrams, charts, graphs, or illustrations. Visuals can be particularly effective when you are trying to explain a complex process or system, as they can provide a clear, easy-to-follow representation of the subject.&lt;/p&gt;

&lt;h2 id=&quot;incorporate-storytelling&quot;&gt;Incorporate storytelling&lt;/h2&gt;

&lt;p&gt;While technical writing is often associated with dry language, incorporating storytelling can make your writing more engaging and accessible. This could involve using anecdotes, case studies, or narratives to illustrate your points. Techniques like metaphors, extended analogies, and other techniques can be valuable ways to explain complex topics or frame a concept in a new way. By using storytelling, you can help your readers understand the subject on a deeper level.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Technical writing is an essential skill for anyone working in a complex field, or marketing to experts. By following these tips, you can ensure that your technical writing is clear, concise, and easy to understand, helping you to communicate your ideas more effectively to your intended audience.&lt;/p&gt;

&lt;p&gt;A few parting questions to consider:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Are there any examples of technical writing that you particularly admire What made it stand out, and what lessons can be learned from its approach to technical writing?&lt;/li&gt;
  &lt;li&gt;What are some strategies for using visuals effectively in technical writing&lt;/li&gt;
  &lt;li&gt;Are there any tips you would add to the list above?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;additional-resources&quot;&gt;Additional Resources&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.samjulien.com/how-to-get-started-with-technical-writing&quot;&gt;How to Get Started with Technical Writing&lt;/a&gt; – tips for building your technical writing skills and portfolio&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://thenewstack.io/a-software-developers-guide-to-technical-writing/&quot;&gt;A Software Developer’s Guide to Technical Writing&lt;/a&gt; – useful tips for anyone interested in writing for software developers&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hemingwayapp.com/&quot;&gt;Hemingway Editor&lt;/a&gt; – an excellent resource for sharpening your writing and removing those pesky adverbs&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Thoughts on open-ended writing</title>
   <link rel="alternate" href="https://andrewstiefel.com/some-thoughts-open-ended-writing/"/>
   <published>2023-03-03T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/some-thoughts-open-ended-writing</id>
   <summary>Open-ended writing connects ideas and identifies new questions. It encourages conversation instead of presenting a polished argument.</summary>
   <content type="html">&lt;p&gt;Writing online, especially for a blog, can feel difficult. Especially for a (recovering) social media and content marketer like myself. Yes, it’s easy to make a blog. It seems like there are constantly new tools popping up promising to help you blog, build a newsletter, or post on social media.&lt;/p&gt;

&lt;p&gt;But writing is a different matter. Today it seems like blogging is focused on producing capital “C” Content for consumption. Everything becomes an “ultimate guide to X,” even if you try to use slightly more tasteful titles. With the arrival of Chat-GPT and other AI tools, the world is faced with even more bland and repetitive capital “C” content as the “&lt;a href=&quot;https://onezero.medium.com/the-dark-forest-theory-of-the-internet-7dc3e68a7cb1&quot;&gt;dark forest&lt;/a&gt;” of the web expands, to borrow a term from &lt;a href=&quot;https://www.ystrickler.com/&quot;&gt;Yancey Strickler&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This isn’t inspiring. And it’s rarely enjoyable to write these types of articles.&lt;/p&gt;

&lt;h2 id=&quot;digital-gardening-and-small-b-blogging&quot;&gt;Digital Gardening and Small b Blogging&lt;/h2&gt;

&lt;p&gt;When I started writing on this website (again), I wanted to treat it more like a digital garden. I’d like to expand my thoughts on digital gardening sometime, but I think Maggie Appleton has &lt;a href=&quot;https://maggieappleton.com/garden-history&quot; title=&quot;A Brief History &amp;amp; Ethos of the Digital Garden&quot;&gt;the best working definition&lt;/a&gt; for now:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“A garden is a collection of evolving ideas that aren’t strictly organised by their publication date. They’re inherently exploratory – notes are linked through contextual associations. They aren’t refined or complete - notes are published as half-finished thoughts that will grow and evolve over time. They’re less rigid, less performative, and less perfect than the personal websites we’re used to seeing.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This approach resonates with me. Mainly because producing exhaustive articles is, well, exhausting. This definition of the digital garden is similar to the concept of “&lt;a href=&quot;https://tomcritchlow.com/2018/02/23/small-b-blogging/&quot; title=&quot;Small B Blogging&quot;&gt;small b blogging&lt;/a&gt;” introduced by Tom Critchlow:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“Small b blogging is learning to write and think with the network. Small b blogging is writing content designed for small deliberate audiences and showing it to them. Small b blogging is deliberately chasing interesting ideas over pageviews and scale. An attempt at genuine connection vs the gloss and polish and mass market of most content marketing.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I recently read another note by Tom Critchlow that was the direct inspiration for this line of thinking, entitled “&lt;a href=&quot;https://tomcritchlow.com/2023/02/10/riffs/&quot;&gt;Writing, Riffs, and Relationships&lt;/a&gt;.” There are lots of good concepts in the article, but the idea of &lt;em&gt;making writing small&lt;/em&gt; stood out to me. In particular&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“People’s first instinct with content is to try and make it polished and closed. To be useful by solving something or creating the ultimate guide to something. Those pieces of content can be good - but they’re very hard to write, and even harder to write well! Instead I prefer to take a more inquisitive and open-ended approach….”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“Closed writing is boring writing. If you’ve fully explored and put to bed the topic you’re writing about then there’s very little left for someone to react to. “Nice post” someone might say.&lt;/em&gt;&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;But if you deliberately leave some rough edges, some threads that the reader can pull on, then you’re inviting the reader into the conversation. You’re saying (possibly explicitly!) - “Hey, what are your thoughts on this topic? How do you think about it?”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Critchlow goes on to recommend ending a blog post or “riff” with more questions that encourage you (and your audience) to explore other topics. Altogether, this made me think about the difference between open-ended and closed writing and how they are different modes of writing altogether.&lt;/p&gt;

&lt;h2 id=&quot;a-brief-definition-of-open-ended-writing&quot;&gt;A Brief Definition of Open-Ended Writing&lt;/h2&gt;

&lt;p&gt;Open-ended writing seeks to connect ideas and identify new pathways of inquiry. It explores a topic by connecting sources and identifying tensions, conflicts, or missing information. Open-ended writing invites conversation and debate.&lt;/p&gt;

&lt;p&gt;In practice, open-ended writing is defined by three basic activities: free writing, summarizing, and questioning:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Free writing introduces sources, ideas, and questions and starts to connect them together.&lt;/li&gt;
  &lt;li&gt;Summarizing organizes the information into a statement of what is known so far and what has been covered.&lt;/li&gt;
  &lt;li&gt;Questioning identifies tensions and gaps that could be explored further in the future or invites areas of conversation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;some-spring-cleaning&quot;&gt;Some Spring Cleaning&lt;/h2&gt;

&lt;p&gt;I started this blog to write small, informal blog posts. So far I’ve fallen back into the trap of writing “articles” that don’t really encourage conversation or provide new threads to pull on. While it’s not critical for doing the actual writing, I decided to re-classify my digital garden to encourage myself to focus more on riffs and notes.&lt;/p&gt;

&lt;p&gt;Previously, I had two categories: &lt;strong&gt;Notes&lt;/strong&gt; and &lt;strong&gt;Essays&lt;/strong&gt;. Notes were supposed to be objective and focused on single topics; essays would pull together multiple notes to present a specific point of view. Obviously, neither category encouraged exploratory writing. I generally wrote less and focused on polishing my notes, which were supposed to be the rough form of writing. I seldom got around to writing essays.&lt;/p&gt;

&lt;p&gt;I now have my digital garden organized into three categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://andrewstiefel.com/notes/&quot;&gt;Notes&lt;/a&gt;&lt;/strong&gt;– Open-ended, exploratory riffs that connect 2-3 ideas or sources together. These are the heart of the digital garden.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://andrewstiefel.com/articles/&quot;&gt;Articles&lt;/a&gt;&lt;/strong&gt; – Closed writing that thoroughly explores a single topic from a mostly objective point of view.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://andrewstiefel.com/essays/&quot;&gt;Essays&lt;/a&gt;&lt;/strong&gt; – Utilizes either open-ended or closed writing to explore a single subject from a personal point of view.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;how-do-you-practice-open-ended-writing&quot;&gt;How do you practice open-ended writing?&lt;/h2&gt;

&lt;p&gt;This particular post might be my first true note. It’s not meant to be comprehensive and it’s mostly my attempt to work out (in public) an approach to open-ended writing.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What do you find hard or challenging about writing?&lt;/li&gt;
  &lt;li&gt;Does changing the purpose to open-ended writing encourage you to write more? Or does it scare you?&lt;/li&gt;
  &lt;li&gt;Do you use a public platform or a private one? Is one better than the other, or are they just different?&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Pocket guide to privacy-first email newsletter software</title>
   <link rel="alternate" href="https://andrewstiefel.com/privacy-first-email-newsletter-software/"/>
   <published>2023-02-09T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/privacy-first-email-newsletter-software</id>
   <summary>A handy guide to privacy-first email newsletter services that protect user privacy by turning off open and click tracking by default.</summary>
   <content type="html">&lt;p&gt;When I first started to look for privacy-first email newsletter options back in 2019, there just weren’t many options. There were great privacy-first website analytics tools like &lt;a href=&quot;https://usefathom.com/ref/FBJDFZ&quot; title=&quot;Fathom Analytics&quot; data-fathom=&quot;Referral click&quot; target=&quot;_blank&quot;&gt;Fathom Analytics&lt;/a&gt;, but nothing for email. Nearly every provider required tracking pixels by default.&lt;/p&gt;

&lt;p&gt;I want to briefly acknowledge that there are some legitimate reasons why email newsletter software providers might require pixels. Tracking pixels are one way to evaluate a sender’s reputation and ensure overall deliverability for everyone using their platform. Higher open and click rates indicate that a list is engaged. The reverse could indicate that an account is sending spam emails.&lt;/p&gt;

&lt;p&gt;The problem is that tracking pixels collect far too much information, including exact location information from each recipient. Most of us understandably don’t want senders to know where we read an email, how many times we read that email, what links we clicked, and how many times we clicked each link.&lt;/p&gt;

&lt;p&gt;There are, of course, other ways to evaluate list engagement. Unsubscribes and spam reports are a clear signal – and they are the indicators that matter most. As a sender, you can evaluate email engagement by website traffic, list growth, unsubscribes, spam reports, and other methods.&lt;/p&gt;

&lt;p&gt;The good news is that over the past year or two many major email newsletter providers have started to let you turn off email trackers (e.g. MailChimp, but with limitations). Other providers still do not (e.g. ConvertKit).&lt;/p&gt;

&lt;h2 id=&quot;privacy-first-email-newsletter-services&quot;&gt;Privacy-First Email Newsletter Services&lt;/h2&gt;
&lt;p&gt;I wanted a provider that offered a privacy-first by default platform. So I compiled a list and I’m sharing it here. My criteria for inclusion in this list were simple:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Open and click tracking are turned off by default&lt;/li&gt;
  &lt;li&gt;Does not use Google ReCaptcha on the subscription form&lt;/li&gt;
  &lt;li&gt;Does not have third-party trackers (e.g. Google Analytics) on their website&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is a list of the email newsletter services that met the criteria, as well as their lowest price point as of February 9, 2023:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Company&lt;/th&gt;
      &lt;th&gt;Tracking&lt;/th&gt;
      &lt;th&gt;HQ Location&lt;/th&gt;
      &lt;th&gt;Cheapest Plan&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Buttondown&lt;/td&gt;
      &lt;td&gt;Off by default&lt;/td&gt;
      &lt;td&gt;US&lt;/td&gt;
      &lt;td&gt;Free up to 100 subscribers&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SendStack&lt;/td&gt;
      &lt;td&gt;None&lt;/td&gt;
      &lt;td&gt;EU&lt;/td&gt;
      &lt;td&gt;Free up to 100 subscribers&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;MailCoach&lt;/td&gt;
      &lt;td&gt;Off by default&lt;/td&gt;
      &lt;td&gt;EU&lt;/td&gt;
      &lt;td&gt;$9.99&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;buttondown&quot;&gt;Buttondown&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://buttondown.email/refer/andrewstiefel&quot; title=&quot;Buttondowm&quot; target=&quot;_blank&quot; data-fathom=&quot;Referral click&quot;&gt;Buttondown&lt;/a&gt; is a minimalist tool for writing and producing email newsletters. Based in the United States, it is run as an indie software business. Buttondown gets a lot of things right, like privacy-first by default (you can, however, opt-in to tracking if you want), the ability to write in markdown, RSS-to-Email tools so you can run your own version of Substack, and a first-party API that is included in the free plan for the hackers among us.&lt;/p&gt;

&lt;h2 id=&quot;sendstack&quot;&gt;SendStack&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://getsendstack.com/&quot; title=&quot;SendStack&quot; target=&quot;_blank&quot;&gt;SendStack&lt;/a&gt; is one of the newest tools and was released by a team based in the European Union (Germany, specifically). It has fewer features than Buttondown but a much friendlier user interface. They also make their first-party API available to free plans, which is a great feature for developers or anyone wanting to &lt;a href=&quot;https://andrewstiefel.com/netlify-functions-email-subscription/&quot;&gt;build their own first-party email newsletter subscription form&lt;/a&gt;. SendStack takes a much harder line on automation, however, so there is no RSS-to-Email function or other automation tools.&lt;/p&gt;

&lt;h2 id=&quot;mailcoach&quot;&gt;MailCoach&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://mailcoach.app/&quot; title=&quot;MailCoach&quot; target=&quot;_blank&quot;&gt;MailCoach&lt;/a&gt; offers both a hosted and a cloud-based solution. Interestingly, they also support transactional email. Like the other platforms here they offer a streamlined interface. But unlike Buttondown and SendStack, automation and transactional email are treated as important features. This is a good solution if you need more than just a newsletter, and would be a great option for agencies, businesses, or anyone building more complex email workflows.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I have personally used Buttondown and SendStack, but I haven’t tried MailCoach yet. This isn’t an endorsement of any particular service. You should try them out and see what works best for you. I also recommend this article comparing &lt;a href=&quot;https://blog.daniemon.com/2022/11/15/privacy-first-newsletters-transactional-emails/&quot; title=&quot;Pricing Comparison&quot; target=&quot;_blank&quot;&gt;pricing models for privacy-first email newsletter services&lt;/a&gt; if you are considering one of these platforms.&lt;/p&gt;

&lt;p&gt;But, if you’ve been looking for a private alternative to Mailchimp and similar services, you now have a handful to choose from. I’m looking forward to seeing this space grow as more creators and businesses start to adopt privacy-first marketing practices in the future.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Tools I'm using right now</title>
   <link rel="alternate" href="https://andrewstiefel.com/tools/"/>
   <published>2022-08-30T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/tools</id>
   <summary>Here is a list of my favorite tools for marketing, writing, and knowledge management.</summary>
   <content type="html">&lt;p&gt;I’m always curious what tools people use in their work, so I thought it would compile a list of the tools I use for writing and productivity.&lt;/p&gt;

&lt;p&gt;With that being said, use what you’re comfortable using or already know how to use. Outcomes are the most important; whatever tools you pick should help you get to the outcomes you want.&lt;/p&gt;

&lt;p&gt;But there is a reason why we find tools fascinating. Tools can influence those outcomes, sometimes in a significant way! At least Abraham Lincoln thought so:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If I only had an hour to chop down a tree, I would spend the first 45 minutes sharpening my axe.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So with that introduction in mind, here’s what I’m using today. Hope you enjoy it!&lt;/p&gt;

&lt;h2 id=&quot;personal-productivity&quot;&gt;Personal Productivity&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://pr.tn/ref/259YMYS9Z3RG&quot;&gt;Proton Mail&lt;/a&gt;: End-to-end enccrypted email for privacy and security&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://culturedcode.com/things/&quot; title=&quot;Cultured Code - Things&quot;&gt;Things&lt;/a&gt;: Personal task management&lt;/p&gt;

&lt;h2 id=&quot;business-management&quot;&gt;Business Management&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://workspace.google.com/&quot; title=&quot;Google Workspace&quot;&gt;Google Workspace&lt;/a&gt;: Custom email domain and a business phone number&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.waveapps.com/&quot; title=&quot;Wave Accounting&quot;&gt;Wave&lt;/a&gt;: Free accounting for small businessess&lt;/p&gt;

&lt;h2 id=&quot;knowledge-management&quot;&gt;Knowledge Management&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://obsidian.md/&quot; title=&quot;Obsidian&quot;&gt;Obsidian&lt;/a&gt;: Notes stored in markdown and synced with end-to-end encryption&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://readwise.io/&quot;&gt;Readwise&lt;/a&gt;: One app for feeds, reading, and highlighting&lt;/p&gt;

&lt;h2 id=&quot;marketing&quot;&gt;Marketing&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://buffer.com/&quot; title=&quot;Buffer&quot;&gt;Buffer&lt;/a&gt;: For scheduling social media posts&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://buttondown.email/refer/andrewstiefel&quot; title=&quot;Buttondown&quot; data-fathom=&quot;Referral click&quot;&gt;Buttondown&lt;/a&gt;: Privacy-first email newsletter software&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://usefathom.com/ref/FBJDFZ&quot; title=&quot;Fathom Analytics&quot; data-fathom=&quot;Referral click&quot;&gt;Fathom Analytics&lt;/a&gt;: For privacy-first website analytics&lt;/p&gt;

&lt;h2 id=&quot;web-design&quot;&gt;Web Design&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://jekyllrb.com/&quot; title=&quot;Jekyll&quot;&gt;Jekyll&lt;/a&gt;: Static site generator&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.namecheap.com/&quot; title=&quot;Namecheap&quot;&gt;Namecheap&lt;/a&gt;: For buying domains&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.netlify.com/&quot; title=&quot;Netlify&quot;&gt;Netlify&lt;/a&gt;: For simply, static website hosting&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://tailwindcss.com/&quot; title=&quot;Tailwind CSS&quot;&gt;Tailwind CSS&lt;/a&gt;: Utility-first CSS framework for designing websites&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot; title=&quot;Visual Studio Code&quot;&gt;Visual Studio Code&lt;/a&gt;: Open-source code editing app&lt;/p&gt;

&lt;h2 id=&quot;writing&quot;&gt;Writing&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.copy.ai/&quot; title=&quot;Copy AI&quot;&gt;Copy AI&lt;/a&gt;: Side kick for brainstorming and copywriting&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://ulysses.app/&quot; title=&quot;Ulysses&quot;&gt;Ulysses&lt;/a&gt;: Markdown writing app&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Build an email subscription form with Netlify Functions</title>
   <link rel="alternate" href="https://andrewstiefel.com/netlify-functions-email-subscription/"/>
   <published>2022-08-28T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/netlify-functions-email-subscription</id>
   <summary>Learn how to use Netlify Functions and ConvertKit to create a custom newsletter subscription form for your website.</summary>
   <content type="html">&lt;p&gt;I enjoy the process of building and maintaining my own personal website. It’s a great way to experiment with different technologies, and have fun learning new tools and concepts along the way.&lt;/p&gt;

&lt;p&gt;This time, I wanted to learn how to use &lt;a href=&quot;https://www.netlify.com/blog/intro-to-serverless-functions/&quot; title=&quot;Intro to Serverless Functions – Netlify&quot;&gt;serverless functions&lt;/a&gt;. There are a lot of great resources out there already. But I had trouble finding a guide that adequately addressed my use case: a humble email subscription form.&lt;/p&gt;

&lt;p&gt;This tutorial is strongly inspired by an &lt;a href=&quot;https://css-tricks.com/using-netlify-forms-and-netlify-functions-to-build-an-email-sign-up-widget/&quot; title=&quot;CSS-Tricks&quot;&gt;excellent guide created by Matthew Ström&lt;/a&gt;. I’ve added solutions for some of the problems I encountered while following his guide, but Matthew deserves the credit.&lt;/p&gt;

&lt;h2 id=&quot;the-challenge-build-a-mailing-list-sign-up-form&quot;&gt;The Challenge: Build a Mailing List Sign Up Form&lt;/h2&gt;
&lt;p&gt;After going through all the work to build my personal website, the last thing I wanted to do was slap a pre-designed newsletter subscription form on it.&lt;/p&gt;

&lt;p&gt;I wanted the flexibility to design my own custom forms for a few reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Better design:&lt;/strong&gt; Email marketing providers offer great default forms, but they never perfectly match a site’s design&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Better Performance:&lt;/strong&gt; External email forms require additional calls for CSS and Javascript, and they sometimes get blocked by privacy settings&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Better privacy:&lt;/strong&gt; Hosted email forms can collect additional information about users, like their IP address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I set out a few rules for this challenge:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It should work without extra JavaScript or AJAX&lt;/li&gt;
  &lt;li&gt;It must use &lt;a href=&quot;https://docs.netlify.com/functions/overview/&quot; title=&quot;Netlify Functions Overview&quot;&gt;Netlify functions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;It shouldn’t need external dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-team-jekyll-netlify-and-convertkit&quot;&gt;The Team: Jekyll, Netlify, and ConvertKit&lt;/h2&gt;
&lt;p&gt;My website is built using a static site generator called &lt;a href=&quot;https://jekyllrb.com/&quot; title=&quot;Jekyll&quot;&gt;Jekyll&lt;/a&gt;. It allows me to build my own templates and components, so I’ll use it to build my email form. I also used &lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss-forms&quot; title=&quot;Github – Tailwind CSS Forms&quot;&gt;Tailwind CSS Forms Plugin&lt;/a&gt; to simplify the design process.&lt;/p&gt;

&lt;p&gt;I use a service called &lt;a href=&quot;https://www.netlify.com/&quot; title=&quot;Netlify&quot;&gt;Netlify&lt;/a&gt; to deploy my website. It’s key for this project, because it complies the static assets built by Jekyll and runs the serverless function to send emails to my email list provider.&lt;/p&gt;

&lt;p&gt;Finally, I’m using &lt;a href=&quot;https://convertkit.com/&quot; title=&quot;ConvertKit&quot;&gt;ConvertKit&lt;/a&gt; as my email list provider. I’ve also included information on how to use &lt;a href=&quot;https://buttondown.email&quot; title=&quot;Buttondown&quot;&gt;Buttondown&lt;/a&gt; and &lt;a href=&quot;https://getsendstack.com/&quot; title=&quot;SendStack&quot;&gt;SendStack&lt;/a&gt; in this tutorial, but the basic principles of the function should apply to any other email providers that offers an API.&lt;/p&gt;

&lt;p&gt;Ok, let’s get started!&lt;/p&gt;

&lt;h2 id=&quot;create-the-serverless-function&quot;&gt;Create the serverless function&lt;/h2&gt;
&lt;p&gt;You need to follow three basic steps to create a Netlify function:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add API tokens to Netlify as environment variables via the admin interface&lt;/li&gt;
  &lt;li&gt;Tells Netlify where to look for your functions using the netlify.toml file 3. Write the function in a Javascript file in your project&lt;/li&gt;
  &lt;li&gt;Write the function as a Javascript file in your project&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To start, let’s save the API token from our email service as an &lt;strong&gt;environment variable&lt;/strong&gt;. Environment variables are useful to hold information that I don’t want to make public, like this API key. You can add an environment variable using the Netlify admin interface under your build and deploy settings.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/netlify-environment-variables.png&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/netlify-environment-variables.png&quot; alt=&quot;Netlify environment variables&quot; width=&quot;1880&quot; height=&quot;782&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, specify where Netlify should look for your functions. Edit your netlify.toml to specify the functions directory. It might look something like this:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;base = &quot;.&quot;&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;functions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;directory = &quot;netlify/functions/&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a function file in the directory you specified above. If you used the default functions directory, you should save your function at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YOUR_BASE_DIRECTORY/netlify/functions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, you’ll need to give your function a name. For example, to create a function with an endpoint name of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello-world&lt;/code&gt;, save the function in one of these locations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netlify/functions/hello-world.js&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netlify/functions/hello-world/hello-world.js&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netlify/functions/hello-world/index.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this tutorial, I’m going to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submission-created&lt;/code&gt; event trigger. Netlify will run my function every time a form is submitted. To do that, I’m going to name my function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submission-created.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now you’re ready to start writing the function. Start by importing the API key you created earlier as an environment variable:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EMAIL_TOKEN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On line 2, I add a small library called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-fetch&lt;/code&gt;. This allows me to use Javascript’s Fetch API, which is how we’ll format an API POST request to send data to our email service.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;node-fetch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;NOTE: When I was writing this post, many of the tutorials available used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; method to import the Fetch API which resulted in errors when I tried to deploy the function. Make sure you use the method I described above. If you upgrade to node-fetch v3, you’ll also need to update either your netlify.toml file or package.json to use ESM.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;functions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;node_bundler = &quot;esbuild&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can find more information about &lt;a href=&quot;https://www.netlify.com/blog/how-to-make-a-fetch-request-using-node-fetch-v3/&quot; title=&quot;Netlify Blog&quot;&gt;how to make a fetch request using node-fetch v3&lt;/a&gt; in an excellent guide by Tatyana Novell on the Netlify blog.&lt;/p&gt;

&lt;p&gt;Next create a synchronous function on line 4. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exports.handler&lt;/code&gt; value is where Netlify expects to find the function, so I define it there. The basic syntax to create the function is provided below:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;function &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// your server-side functionality&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next retrieve the email from the event value using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.parse&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then log the data in the console for debugging:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Received a submission: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After retrieving the email address from the event value using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.parse&lt;/code&gt;, I’m ready to send it off my email marketing providers. I’ll use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-fetch&lt;/code&gt; library I imported earlier to form the POST request.&lt;/p&gt;

&lt;p&gt;I’ve outlined code examples for a few services below, but make sure you consult the API documentation from your email provider to make sure the API request is properly format.&lt;/p&gt;

&lt;h3 id=&quot;convertkit-subscription-form&quot;&gt;ConvertKit Subscription Form&lt;/h3&gt;
&lt;p&gt;Using ConvertKit as an example, send a POST request to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://api.convertkit.com/v3/forms/&amp;lt;YOUR_FORM_ID/subscribe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To find the form ID, navigate to &lt;strong&gt;Grow &amp;gt; Landing Pages &amp;amp; Forms&lt;/strong&gt;, select the form you want to use, and copy the ID number from the url:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://app.convertkit.com/forms/designers/&lt;span class=&quot;nt&quot;&gt;&amp;lt;YOUR_FORM_ID&amp;gt;&lt;/span&gt;/edit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The body of the POST request contains the email token and the email address from the form submission:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://api.convertkit.com/v3/forms/&amp;lt;YOUR_FORM_ID/subscribe&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; 
		&lt;span class=&quot;na&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EMAIL_TOKEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;buttondown-subscription-form&quot;&gt;Buttondown Subscription Form&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://buttondown.email/refer/andrewstiefel&quot; data-fathom=&quot;Referral click&quot;&gt;Buttondown’s API&lt;/a&gt; sends the authorization in the headers rather than the body, so you’ll need to adapt the code slightly:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://api.buttondown.email/v1/subscribers&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;Authorization&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Token &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EMAIL_TOKEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;sendstack-subscription-form&quot;&gt;SendStack Subscription Form&lt;/h3&gt;
&lt;p&gt;SendStack is a new privacy-first email service. Unlike Buttondown and ConvertKit, they offer API access on their free plan. There is currently a waiting list, but if you have access, you can try it out using the code below.&lt;/p&gt;

&lt;p&gt;Add the email token to the headers and the email address to the body of the POST request:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://getsendstack.com/api/subscribers&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;na&quot;&gt;Authorization&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Bearer &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;EMAIL_TOKEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then capture and log the response from the email service. We do this to diagnose any issues that happened. Netlify makes it easy to check your function’s logs, so use console.log often!&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Response:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, redirect the form to a confirmation page that tells subscribers to check their emails to confirm their subscription. Use a simple return to redirect the browser to the new page:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;302&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    	&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/confirmation/,
	},
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can find the completed function below. In this case I used ConvertKit:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EMAIL_TOKEN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;node-fetch&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Received a submission: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fetch &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://api.convertkit.com/v3/forms/{YOUR_FORM-ID}/subscribe&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Content-Type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; 
                &lt;span class=&quot;na&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EMAIL_TOKEN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;email&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseText&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;response:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;302&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Location&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/confirmation/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;create-the-email-subscription-form&quot;&gt;Create the email subscription form&lt;/h2&gt;
&lt;p&gt;Now that you’ve built the function, let’s call it from the email subscription form. The HTML for the email subscription form is very minimal.&lt;/p&gt;

&lt;p&gt;All you need to do is call the function using the form action:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;newsletter&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;action=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/.netlify/functions/subscribe-email&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Your Email Address&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;placeholder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Address&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Subscribe&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make sure you specific input name (“email”) and make sure it matches the information you parse from the event value using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.parse&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;submission-created&lt;/code&gt; trigger for your function like I did, you’ll need to change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;form&amp;gt;&lt;/code&gt; field slightly by adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data-netlify=&quot;true&quot;&lt;/code&gt; to tell Netlify to process this form:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;newsletter&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;method=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-netlify=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Your Email Address&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;placeholder=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Address&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Subscribe&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;deploy-the-function&quot;&gt;Deploy the function&lt;/h2&gt;
&lt;p&gt;Now that I’ve written my function, configured my netlify.toml file, and added my environment variables, everything is ready to go. Deploying is painless: just set up Netlify’s GitHub integration, and your function will be deployed when your project is pushed.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;It took less than 50 lines of code to create my own email subscription form including custom HTML and a serverless function to add new emails to my list. I wrote it all in HTML, CSS, and JavaScript, and everything is served from my domain. Plus, my website visitors get a nice experience whether they have JavaScript enabled or not, and it will still serve even if they have advanced privacy protection enabled.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Just start</title>
   <link rel="alternate" href="https://andrewstiefel.com/just-start/"/>
   <published>2022-06-28T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/just-start</id>
   <summary>How long have you been working on a project with nothing to show?</summary>
   <content type="html">&lt;p&gt;How long have you been working on a project with nothing to show?&lt;/p&gt;

&lt;p&gt;I am an expert procrastinator. I spent three years building, tearing down, and restarting this blog. The colors were never right, I didn’t like the font, I needed just one more feature to be ready.&lt;/p&gt;

&lt;p&gt;Finally, I decided to slim down to just what I need to write. The rest could come later. For now It’s minimal, but it’s all I needed to start.&lt;/p&gt;

&lt;p&gt;Today you can publish your writing in less than five minutes. Start with tools like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/&quot; title=&quot;Medium&quot; target=&quot;_blank&quot;&gt;Medium&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://substack.com/&quot; title=&quot;Substack&quot; target=&quot;_blank&quot;&gt;Substack&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://convertkit.com/&quot; title=&quot;ConvertKit&quot; target=&quot;_blank&quot;&gt;ConvertKit&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ghost.org/&quot; title=&quot;Ghost&quot; target=&quot;_blank&quot;&gt;Ghost&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wordpress.com/&quot; title=&quot;Wordpress&quot; target=&quot;_blank&quot;&gt;Wordpress&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list is endless. So what are you waiting for?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Start writing&lt;/li&gt;
  &lt;li&gt;Get feedback&lt;/li&gt;
  &lt;li&gt;Refine your work&lt;/li&gt;
  &lt;li&gt;Try again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the biggest misconceptions about writing or creating anything is that you should start with a strategy: “I’m going to write about X for people interested in Y.”&lt;/p&gt;

&lt;p&gt;But here’s the truth: you don’t need a plan to start.&lt;/p&gt;

&lt;p&gt;Write about whatever interests you. You’ll eventually find what you enjoy writing about the most and what resonates most with your audience.&lt;/p&gt;

&lt;p&gt;You just have to start.&lt;/p&gt;

&lt;p&gt;Here are three formats to get started:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Today I learned how to…&lt;/li&gt;
  &lt;li&gt;Did you read or hear about X? Here’s my reaction…&lt;/li&gt;
  &lt;li&gt;Someone asked me about X, so here is the answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep a notebook with all the questions people ask you for help with. Write up your answers and publish them.&lt;/p&gt;

&lt;p&gt;Eventually you’ll hit your stride — and you’ll probably discover an idea you could never have found while planning your strategy, picking brand colors, and brainstorming topics for your blog.&lt;/p&gt;

&lt;p&gt;Start today.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Why is storytelling important for B2B marketing?</title>
   <link rel="alternate" href="https://andrewstiefel.com/storytelling-important-B2B-marketing/"/>
   <published>2022-06-22T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/storytelling-important-B2B-marketing</id>
   <summary>B2B storytelling helps unify groups of people around a shared narrative about what they need to accomplish.</summary>
   <content type="html">&lt;p&gt;Storytelling has been a buzzword in consumer marketing (B2C) for nearly a decade. And for a good reason. We, as humans, can’t help but tell stories. They are a critical way to convey information and build common ground.&lt;/p&gt;

&lt;h2 id=&quot;storytelling-in-b2c-marketing&quot;&gt;Storytelling in B2C Marketing&lt;/h2&gt;

&lt;p&gt;When I think about storytelling in marketing, emotional, high-production ads from companies like Apple, Coca-Cola, REI, and Starbucks come to mind.&lt;/p&gt;

&lt;p&gt;You’ve probably seen examples, especially around the Super Bowl or other significant events. For instance, in this 2015 advertisement, Apple uses Robin Williams’ speech from &lt;em&gt;Dead Poets Society&lt;/em&gt;  to sell the iPad Air.&lt;/p&gt;

&lt;div class=&quot;aspect-w-16 aspect-h-9&quot;&gt;
  &lt;iframe src=&quot;https://player.vimeo.com/video/112042156?h=c9de6161d7&amp;amp;title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; class=&quot;w-full h-full&quot; frameborder=&quot;0&quot; allow=&quot;autoplay; fullscreen; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;I may not want to run out and buy an iPad right after watching this, but I do remember the ad. And I feel inspired to create something. That feeling is now associated with Apple and their products. The Apple advertisement is an excellent example of why B2C marketers rely on storytelling to build customer connections and trust.&lt;/p&gt;

&lt;h2 id=&quot;why-storytelling-matters-for-b2b-marketing&quot;&gt;Why Storytelling Matters for B2B Marketing&lt;/h2&gt;

&lt;p&gt;For a long time, B2B marketing has held out as a place filled with dry white papers and ebooks waiting behind lead generation forms.&lt;/p&gt;

&lt;p&gt;But storytelling is even more critical for B2B (enterprise) marketing.&lt;/p&gt;

&lt;p&gt;Unlike most B2C products, in B2B marketing, you are selling to groups of people who need to make a decision together. These diverse groups of individuals have unique needs and problems that need to be solved. In many cases, you may sell to stakeholders whose problems you don’t directly solve (typically C-suite leadership).&lt;/p&gt;

&lt;p&gt;The only way to win a deal with so many people is by first uniting everyone around a common cause that turns their problems into a set of shared obstacles to overcome.&lt;/p&gt;

&lt;p&gt;A successful story must resonate with everyone in the buying process and establish a higher-level mission to solve together.&lt;/p&gt;

&lt;p&gt;Successful B2B marketing starts with a strategic narrative — why your company exists and what you help solve. One of my favorite examples is Microsoft’s new mission under CEO Satya Nadella: to &lt;a href=&quot;https://www.microsoft.com/en-us/about&quot; title=&quot;Statista&quot; target=&quot;_blank&quot;&gt;empower every person and every organization on the planet to achieve more&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Microsoft can apply a simple story to consumer products and business tools. It can reframe whatever Microsoft sells around helping customers achieve a shared goal. That could include better healthcare outcomes, increasing student achievement, or building inclusive workplaces.&lt;/p&gt;

&lt;h2 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h2&gt;

&lt;p&gt;To summarize, storytelling is an essential component of B2B marketing because it is a powerful tool for persuasion that can help align groups of buyers around a shared narrative. With the right story, you can inspire confidence and build trust with your customers.&lt;/p&gt;

&lt;p&gt;Let me know what you think on Twitter and LinkedIn.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How to differentiate your product when you aren’t (really) different</title>
   <link rel="alternate" href="https://andrewstiefel.com/differentiate-product-competition/"/>
   <published>2022-06-21T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/differentiate-product-competition</id>
   <summary>Differentiation is about setting your product apart from your competition. But what if your product isn't really different?</summary>
   <content type="html">&lt;p&gt;Product differentiation communicates the unique qualities of your brand or product to distinguish it from your competition.&lt;/p&gt;

&lt;p&gt;But what if your product isn’t unique?&lt;/p&gt;

&lt;p&gt;Today plenty of products go to market without unique features. In the early days of B2B software, it was common to have features that no one else had in the market. Differentiation was reasonably straightforward. You would identify the unique benefit your feature provided for customers and craft a positioning statement around it.&lt;/p&gt;

&lt;p&gt;In today’s technology landscape, differentiation with features is rare — everyone has similar functionality.&lt;/p&gt;

&lt;p&gt;For example, you probably own a smartphone. &lt;a href=&quot;https://www.statista.com/statistics/266572/market-share-held-by-smartphone-platforms-in-the-united-states/&quot; title=&quot;Statista&quot; target=&quot;_blank&quot;&gt;Maybe you even own an Apple iPhone like more than 50% of U.S. consumers.&lt;/a&gt; But can you tell me the difference between the screen resolution on your iPhone versus a Samsung Galaxy? Are they even different?&lt;/p&gt;

&lt;p&gt;Your opinion of that question is likely influenced by brand differentiation more than the unique qualities of either phone. Do you know how many pixels are in a Retina display? Or how that’s different than the screen on a Samsung phone?&lt;/p&gt;

&lt;p&gt;It’s easier than ever for competitors to copy your product. But does that mean you shouldn’t build a great product? Nope.&lt;/p&gt;

&lt;p&gt;It just means that a great product is table stakes.&lt;/p&gt;

&lt;p&gt;Companies that are beating their competitors have a great product and build a unique market position.&lt;/p&gt;

&lt;p&gt;Here’s how you differentiate your product from the competition:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#target-a-niche-market-segment&quot;&gt;Target a niche market segment&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#tell-a-differentiated-story&quot;&gt;Tell a differentiated story&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#provide-valuable-education&quot;&gt;Provide valuable education&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#build-a-community-around-your-vision&quot;&gt;Build a community around your vision&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cultivate-a-partner-ecosystem&quot;&gt;Cultivate a partner ecosystem&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#amplify-employee-advocacy&quot;&gt;Amplify employee advocacy&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each takes time to build. But don’t get intimidated—that’s the point. Your competition cannot easily duplicate your work.&lt;/p&gt;

&lt;p&gt;Let’s explore how you can differentiate your product even when your products don’t have any unique features.&lt;/p&gt;

&lt;h2 id=&quot;target-a-niche-market-segment&quot;&gt;Target a niche market segment&lt;/h2&gt;
&lt;p&gt;The first mistake many companies make is targeting too large a market. When you’re trying to please everyone, you please no one.&lt;/p&gt;

&lt;p&gt;Success starts by narrowing in on a niche in the market that isn’t being served well by current solutions. If you’re familiar with &lt;a href=&quot;https://amzn.to/3Oy7LtO&quot; title=&quot;Amazon&quot; id=&quot;clickAff&quot; target=&quot;_blank&quot;&gt;Geoffrey Moore’s book &lt;em&gt;Crossing the Chasm&lt;/em&gt;&lt;/a&gt;, you might recognize this approach by another name – “land and expand.”&lt;/p&gt;

&lt;p&gt;You may have to niche down a few times to find the right fit in the market, progressively narrowing in on a smaller and smaller customer niche each time.&lt;/p&gt;

&lt;p&gt;But wait, you might ask, don’t I want a bigger audience?&lt;/p&gt;

&lt;p&gt;Eventually, maybe you will. But not when you are struggling to gain traction with your first customers. The more specific and targeted you can be with your positioning and messaging, the more your product will resonate with your customers.&lt;/p&gt;

&lt;p&gt;I think ConvertKit is an excellent example of the niche-down approach. When Nathan Barry started the company, he targeted anyone who needed email marketing. As a result, he was up against heavyweights like MailChimp, ActiveCampaign, and others. And he was failing to gain traction.&lt;/p&gt;

&lt;p&gt;Instead of giving up, he narrowed his market to target professional bloggers and worked to address their problems. He gradually expanded to other digital creators as he gained traction with bloggers. Today the business operates at over $100,000 monthly recurring revenue (MRR).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/nathanbarry/status/1512782207508643845&quot;&gt;Check out Nathan Barry’s Twitter thread&lt;/a&gt;c for more about his journey building ConvertKit.&lt;/p&gt;

&lt;h2 id=&quot;tell-a-differentiated-story&quot;&gt;Tell a differentiated story&lt;/h2&gt;
&lt;p&gt;When trying to differentiate your business, the most crucial question is not “what makes our product better than others?” Instead, it’s “why should customers care?”&lt;/p&gt;

&lt;p&gt;The most successful businesses don’t just sell products; they tell stories and motivate customers to buy into their vision. Instead of discussing what features make your product so great, talk about why it matters. Great stories are never about your products or services. They are about how people use your products and services to improve their lives.&lt;/p&gt;

&lt;p&gt;If you are a B2B company, tell the story about how your customers use your products or services uniquely. If you are B2C, tell the story of how consumers use your products or services to improve their lives.&lt;/p&gt;

&lt;p&gt;Whatever story you tell, ensure it provides a unique point of view on the market you are targeting. For example, how do you understand the market? What is your unique take on how to address challenges within your space?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.drift.com/&quot; title=&quot;Drift&quot; target=&quot;_blank&quot;&gt;Drift&lt;/a&gt; is an excellent example of how this can work in practice. They offer chatbots for customer service. But instead of focusing on automation, they invented a new category for their product named “conversational marketing.” They worked to build leadership within that term and created a stronghold in the market despite competition from other vendors in the space.&lt;/p&gt;

&lt;p&gt;Check out this HubSpot blog post with examples of &lt;a href=&quot;https://blog.hubspot.com/insiders/branding-differentiation&quot; title=&quot;Hubspot&quot; target=&quot;_blank&quot;&gt;10 companies that brilliantly differentiated themselves from the competition&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;provide-valuable-education&quot;&gt;Provide valuable education&lt;/h2&gt;
&lt;p&gt;Educate your audience about the trends and challenges you see in the market, how they can solve their problems, and how to get the most value from your product to solve those challenges.&lt;/p&gt;

&lt;p&gt;The key is to help your customers. Whatever you create (blog, video, ebook, podcast, etc.) should help your customers learn something new. You can even take this further and provide certification or verification that they have learned a specific skill. For example, how to use your product (Microsoft Azure Fundamentals) or a particular set of skills (HubSpot Inbound Marketing).&lt;/p&gt;

&lt;p&gt;My favorite example of education is &lt;a href=&quot;https://buffer.com/&quot; title=&quot;Buffer&quot; target=&quot;_blank&quot;&gt;Buffer&lt;/a&gt;, especially in its early days as a company around 2012–2016. Their blog consistently published valuable content about social media strategy and tactics. Then they shared it via newsletter and social media.&lt;/p&gt;

&lt;p&gt;Personally, Buffer’s blog was invaluable when I was starting a career as a social media manager. At that time, there were no college programs or classes for digital marketing. And there weren’t that many other people who had much experience yet either. Nevertheless, we were all learning on the job. Buffer filled a gap by breaking down trends from their data and offering actionable tips daily.&lt;/p&gt;

&lt;h2 id=&quot;build-a-community-around-your-vision&quot;&gt;Build a community around your vision&lt;/h2&gt;
&lt;p&gt;You need to do more than publish content on your blog. It would be best if you found ways to connect with potential customers one-on-one to understand their problems and how you can help.&lt;/p&gt;

&lt;p&gt;One of the best ways to do this is by building a community around your vision. Find where your audience interacts online or in person and gradually join the conversation. If you’re already creating valuable educational content, it should be easy to chime in as questions arise. Eventually, you’ll want your audience to buy in and start sharing your vision.&lt;/p&gt;

&lt;p&gt;Remember that a community can be centralized (Slack, Discord, Facebook Groups) or decentralized (conversations and hashtags on social media).&lt;/p&gt;

&lt;p&gt;Different companies take different approaches depending on what they want to accomplish. For example, Nike, REI, and Starbucks have massive audiences online. As a result, they can rely on social media to amplify their brand messages and drive conversation around their brands. (The REI OptOutside campaign is a great example – people opt-in and interact around it every year.)&lt;/p&gt;

&lt;p&gt;Other brands rely on bringing people together in a centralized space. For example, developer communities often organize around Slack or Discord as a place to discuss problems and share ideas – the VueJS community is a great example.&lt;/p&gt;

&lt;h2 id=&quot;cultivate-a-partner-ecosystem&quot;&gt;Cultivate a partner ecosystem&lt;/h2&gt;
&lt;p&gt;In addition to building a network with your customers, you should try to recruit partners who share your vision or philosophy. There are three main ways that partners can help differentiate your product:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Provide value-added services&lt;/strong&gt;
Partners function as an extension of your organization. By partnering with other companies, you can offer added value to your customers by leveraging their expertise. For example, your partners could provide anything from training and support to custom development and integration services. By providing additional services, partners can help your customers realize the full value of their investment in your product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2) Provide product extensions and integrations&lt;/strong&gt;
Partners can provide extensions to your core product, adding new functionality and features that complement what you build. Integrations help customers build seamless workflows that address their specific use cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3) Generate co-sell opportunities&lt;/strong&gt;
In addition to extending functionality through integrations, partners can generate new sales opportunities by selling your product and theirs together as a bundle. Selling together is especially effective when the two products are complementary rather than competitive (e.g., CRM + marketing automation).&lt;/p&gt;

&lt;p&gt;Once you start noticing how common partnerships are in the market, it’s hard to stop seeing them everywhere. One recent example I came across recently as a business owner was a bank – &lt;a href=&quot;https://www.novo.co/&quot; title=&quot;Novo&quot; target=&quot;_blank&quot;&gt;Novo&lt;/a&gt;. They help small business owners get started with business checking accounts.&lt;/p&gt;

&lt;p&gt;Novo has built a partner ecosystem that helps new business owners get started faster. They offer discounts and integrations with critical partners like Quickbooks for invoicing, Stripe for collecting payments, and HubSpot as a CRM. New customers get access to these additional perks. By building a partner ecosystem, Novo helps drive business for their partners and helps keep customers invested in using Novo as their bank of choice.&lt;/p&gt;

&lt;h2 id=&quot;amplify-employee-advocacy&quot;&gt;Amplify employee advocacy&lt;/h2&gt;
&lt;p&gt;You automatically extend your reach when your employees advocate for your brand through their social ecosystem.&lt;/p&gt;

&lt;p&gt;But more importantly, you can increase trust.&lt;/p&gt;

&lt;p&gt;Customers often look to your employees as the best source of information about your company and products. According to research from Edelman, &lt;a href=&quot;http://www.edelman.com/2015-edelman-trust-barometer/trust-across-industries/trust-in-employee-engagement/&quot; title=&quot;Edelman&quot; target=&quot;_blank&quot;&gt;68% of consumers say they trust technical experts from a company&lt;/a&gt; over the CEO or marketing material.&lt;/p&gt;

&lt;p&gt;So why do customers trust employees?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;They know more about your company and your products than anyone else&lt;/li&gt;
  &lt;li&gt;They know what your product can do – and what it can’t do&lt;/li&gt;
  &lt;li&gt;They know your competition and category and how you fit in&lt;/li&gt;
  &lt;li&gt;And most importantly: they know what matters to your customers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To succeed, you must first build a culture of trust and sharing. Unfortunately, most companies try to buy some software, implement it, and then give up when employees are less than enthusiastic about it.&lt;/p&gt;

&lt;p&gt;A winning example, however, is &lt;a href=&quot;https://www.linkedin.com/company/refine-labs/&quot; title=&quot;LinkedIn&quot; target=&quot;_blank&quot;&gt;Refine Labs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The entire company is active on LinkedIn, sharing insights and commenting on posts about demand generation. Their success isn’t the result of fancy tools — the company’s CEO, Chris Walker, built advocacy into the culture through his leadership, hiring, and coaching of the team. It’s part of their core identity.&lt;/p&gt;

&lt;h2 id=&quot;the-result-a-differentiated-brand&quot;&gt;The result? A differentiated brand&lt;/h2&gt;
&lt;p&gt;The strategies above take time and a dedication to implement. That’s why they are so successful. Unfortunately, most companies fail to sustain the needed work to build a differentiated product and brand.&lt;/p&gt;

&lt;p&gt;So now that you better understand how to differentiate your product, it’s time for action! If your product has no unique features, you can use the strategies above to differentiate your product and company from the competition.&lt;/p&gt;

&lt;p&gt;And if you do have some unique features? Well, don’t stop promoting those just yet! You can still use these strategies to show off what makes your company special.&lt;/p&gt;

&lt;p&gt;Let me know what you think on &lt;a href=&quot;https://twitter.com/intent/tweet?text=https://andrewstiefel.com/differentiate-product-competition/&quot; title=&quot;Twitter&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/shareArticle?mini=true&amp;amp;url=https%3A//andrewstiefel.com&amp;amp;title=&amp;amp;summary=&amp;amp;source=&quot; title=&quot;LinkedIn&quot; target=&quot;_blank&quot;&gt;LinkedIn&lt;/a&gt;. Thanks for reading!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Networking tips for remote and hybrid work</title>
   <link rel="alternate" href="https://andrewstiefel.com/networking-tips-remote-hybrid-job/"/>
   <published>2022-05-25T00:00:00-07:00</published>
   <id>https://andrewstiefel.com/networking-tips-remote-hybrid-job</id>
   <summary>Networking is always a challenge when starting a new job. It's even more critical for success in a remote or hybrid workplace.</summary>
   <content type="html">&lt;p&gt;You’ve finally landed that dream job — and it’s going to involve some (or a lot) of remote work. Maybe it’s your first job, or maybe you just took a position with a new company. Or, like the rest of the world, you and your team have transitioned to working remotely during the pandemic.&lt;/p&gt;

&lt;p&gt;Regardless of the reason, you are now tasked with building relationships with co-workers you rarely see in person.&lt;/p&gt;

&lt;p&gt;I had to onboard remotely twice during the pandemic. It was a much more challenging experience than starting in person. The first weeks can feel lonely, and it takes time to build the visibility and trust you need to drive projects forward.&lt;/p&gt;

&lt;p&gt;That said, I love working remotely. And I’ve learned a few things along the way.&lt;/p&gt;

&lt;p&gt;Here’s how you can network effectively in an era of remote and hybrid work:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#polish-your-linkedin-profile&quot;&gt;Polish your LinkedIn profile&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#schedule-virtual-coffee-meetings&quot;&gt;Schedule virtual coffee meettings&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#engage-with-professional-communities&quot;&gt;Engage with professional communities&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#share-what-you-learn&quot;&gt;Share what your learn&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;polish-your-linkedin-profile&quot;&gt;Polish your LinkedIn profile&lt;/h2&gt;
&lt;p&gt;Your LinkedIn profile isn’t just for finding a job — it’s also your first impression when meeting and networking with colleagues at your new company.&lt;/p&gt;

&lt;p&gt;When I worked in person, I rarely checked my colleagues’ LinkedIn profiles. And why would I? We could chat at our desks or run into each other in the office.&lt;/p&gt;

&lt;p&gt;After onboarding remotely twice during the pandemic, I can say with certainty that your LinkedIn profile matters more than even your resume. It’s the first place people look to understand who you are and what you’re about.&lt;/p&gt;

&lt;p&gt;I use LinkedIn before scheduling meetings with people I haven’t met yet, or during meetings when I encounter someone new, so I can quickly identify their role and what might be important to them.&lt;/p&gt;

&lt;p&gt;Here are some tips on how to optimize your LinkedIn profile:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Write an engaging introduction section&lt;/strong&gt; that explains your career path, professional interests, and scope of responsibilities&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Update your profile regularly&lt;/strong&gt; so that it reflects your current role at the company, key successes and projects, and relevant skills&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Make a great first impression&lt;/strong&gt; with your LinkedIn headshot — it doesn’t need to be fancy but make sure your face is clearly visible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re looking for more tips, I suggest browsing this &lt;a href=&quot;https://www.jobscan.co/linkedin-profile-writing-guide&quot;&gt;comprehensive LinkedIn profile writing guide&lt;/a&gt; from the team at Jobscan.&lt;/p&gt;

&lt;h2 id=&quot;schedule-virtual-coffee-meetings&quot;&gt;Schedule virtual coffee meetings&lt;/h2&gt;
&lt;p&gt;When you first join a company, schedule 1:1 meetings with various stakeholders. I treat these like informal coffee chats and use them as an opportunity to learn about what people are working on, what their priorities are, and how I might work with them on shared goals.&lt;/p&gt;

&lt;p&gt;Be proactive about introductions – don’t wait for others to introduce themselves. You should focus on meeting with your peers just as much, or maybe more, than meeting with different leaders.&lt;/p&gt;

&lt;p&gt;Your goal here is to make sure that people know who you are and what your role is at the company. This helps build relationships early on so that when there are opportunities for collaboration or mentorship later down the road, there will already be a foundation of trust between you and other members of your team.&lt;/p&gt;

&lt;p&gt;Don’t be afraid to ask questions and share ideas! Starting a new role is an exciting time to learn. And most people enjoy being consulted as experts in their areas and are willing to share what they know.&lt;/p&gt;

&lt;p&gt;Once you’ve established a relationship with someone, it’s important to keep up the communication even when you aren’t working together. Connect over Slack or Teams by sharing interesting articles or news, checking in on how they are doing, or chatting about shared interests.&lt;/p&gt;

&lt;p&gt;One of the best things you can do is recognize when someone else is doing something great. Send an email thanking them for their work and letting them know how much you appreciate what they did — especially if it wasn’t necessarily part of their job description. If you’re announcing a major event to your team via Slack or Teams, make sure to tag and thank them in the post.&lt;/p&gt;

&lt;h2 id=&quot;engage-with-professional-communities&quot;&gt;Engage with professional communities&lt;/h2&gt;
&lt;p&gt;The rise of professional communities on Slack, Teams, Discord, and other platforms has created many opportunities to connect with other professionals.&lt;/p&gt;

&lt;p&gt;Find out where your colleagues hang out online and join their communities. Personally, I use the &lt;a href=&quot;https://www.productmarketingalliance.com/join-slack/&quot;&gt;Product Marketing Alliance (PMA) Slack group&lt;/a&gt; as a way to read about product marketing topics, ask questions, and connect with other professionals by answering questions when I can.&lt;/p&gt;

&lt;p&gt;Seek opportunities to attend or present at conferences. These are great opportunities to meet other professionals face-to-face and share experiences. They can even be a great way to network with your team or other people at your company if you can attend as a group.&lt;/p&gt;

&lt;h2 id=&quot;share-what-you-learn&quot;&gt;Share what you learn&lt;/h2&gt;
&lt;p&gt;Even though I worked as a content marketer and social media manager for several years, I’ve always been a bit shy when it comes to writing on my blog or using my social media profiles.&lt;/p&gt;

&lt;p&gt;After starting two remote roles, I now recognize the importance of creating and sharing valuable content in a remote and hybrid work environment. It’s a way to build reputation and network within your organization just as much as it’s a way to network outside your company.&lt;/p&gt;

&lt;p&gt;Be active on social media platforms like LinkedIn or Twitter. Or even better, start a blog, publish a newsletter, or create videos. The goal is to get your voice out in public and get your ideas in front of your co-workers regularly.&lt;/p&gt;

&lt;p&gt;Sharing what you learn in public is a great way to build your reputation and connect with people who might share some of your interests. The more people see your name associated with valuable content, the more likely they are to trust you as an expert and reach out when they have questions or need advice from someone with your background.&lt;/p&gt;

&lt;p&gt;At first, don’t spend time worrying about having a unique angle, beat, or perspective. Just start and tweak as you go. If you’re not sure what to write about, try one of these prompts to get started:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Today I learned how to…&lt;/li&gt;
  &lt;li&gt;My favorite tools for X are…&lt;/li&gt;
  &lt;li&gt;I was thinking about…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last prompt is actually how this post started. I was thinking about how to better network while onboarding into my new role and decided to write this blog post as a way of teaching myself the best way to get started.&lt;/p&gt;

&lt;h2 id=&quot;be-patient&quot;&gt;Be patient&lt;/h2&gt;
&lt;p&gt;Finally, be patient with yourself (and with others). Starting a new job is exciting, and you want to get going right away. Building new relationships takes time, and it’s going to feel lonely at first. If you work remotely, you will have to be ok leading your learning, networking, and career building.&lt;/p&gt;

&lt;p&gt;On the flip side, it is also empowering. Remote and hybrid work environments offer greater flexibility, work-life balance, and autonomy. I love taking a few minutes to grab a cup of coffee from my kitchen, pet my rabbits, and take in the view of my neighborhood rather than the concrete downtown streets before heading back to work.&lt;/p&gt;

&lt;p&gt;Please let me know what you think on Twitter or LinkedIn. Thanks for reading!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>How to style an Atom feed with XSLT</title>
   <link rel="alternate" href="https://andrewstiefel.com/style-atom-xsl/"/>
   <published>2022-01-24T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/style-atom-xsl</id>
   <summary>Create a seamless user experience for your Atom or RSS feed with XLST stylesheets.</summary>
   <content type="html">&lt;p&gt;Maybe it’s nostalgia for the early web, but I love web feeds as a tool for following and reading content. Feeds are privacy-first and put the reader in control: you can opt out any time, choose your tool for reading, and organize them in any way you want.&lt;/p&gt;

&lt;p&gt;But the UX experience is terrible.&lt;/p&gt;

&lt;p&gt;Web feeds are meant to be machine-readable, so most users follow a link to an RSS or Atom feed and end up looking at something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/raw-atom-rss.png&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/raw-atom-rss.png&quot; alt=&quot;Raw RSS or Atom feed&quot; width=&quot;760&quot; height=&quot;483&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This doesn’t have to be the case. RSS and Atom feeds can be human-readable with a little extra work. &lt;a href=&quot;/feed.xml&quot; target=&quot;_blank&quot; data-fathom=&quot;RSS subscription&quot;&gt;Here’s an example from my website&lt;/a&gt;. It’s simple and clean and provides some essential instructions on how to get started:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://andrewstiefel.com/assets/img/human-readable-atom-feed.png&quot; data-lightbox=&quot;&quot; data-full=&quot;https://res.cloudinary.com/andrewstiefel/image/fetch/q_auto,f_auto/https://andrewstiefel.com/assets/img/human-readable-atom-feed.png&quot; alt=&quot;Human-readable Atom or RSS feed&quot; width=&quot;760&quot; height=&quot;483&quot; crossorigin=&quot;anonymous&quot; class=&quot;dark:brightness-75 cursor-pointer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s explore how to implement this with Atom and an XSLT stylesheet.&lt;/p&gt;

&lt;h2 id=&quot;why-atom-and-not-rss&quot;&gt;Why Atom, and not RSS?&lt;/h2&gt;

&lt;p&gt;Great question, and one I don’t intend to answer fully here given the vast amounts of writing on this topic already. In short, Atom is a better format.&lt;/p&gt;

&lt;p&gt;Specifically, I wanted the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Support for a full content payload in the feed&lt;/li&gt;
  &lt;li&gt;Wide support across feed readers&lt;/li&gt;
  &lt;li&gt;Extensibility and future-proof format&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;first-create-the-feed-in-jekyll&quot;&gt;First, create the feed in Jekyll&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you’re using a different tech stack to create your website, you can &lt;a href=&quot;#create-the-xsl-file-to-style-the-feed&quot;&gt;skip this section&lt;/a&gt; and jump ahead to the part about creating an XSLT stylesheet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can either use the excellent &lt;a href=&quot;https://github.com/jekyll/jekyll-feed&quot; title=&quot;Jekyll Feed&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Jekyll Feed plugin&lt;/a&gt;, or create your own template using liquid tags and save it in your project as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feed.xml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I chose to create my own template, so I could incorporate some additional markup. You can see my version below:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
---

&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml-stylesheet href=&quot;/assets/css/feed.xsl&quot; type=&quot;text/xsl&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;feed&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2005/Atom&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

 &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ site.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ site.url }}{{ site.baseurl }}/feed.xml&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;self&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ site.url }}{{ site.baseurl }}/&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;alternate&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;subtitle&amp;gt;&lt;/span&gt;{{ site.description }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/subtitle&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;updated&amp;gt;&lt;/span&gt;{{ site.time | date_to_xmlschema }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/updated&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;{{ site.url }}/&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;author&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;{{ site.author.name }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;email&amp;gt;&lt;/span&gt;{{ site.author.email }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/email&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;/author&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;rights&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Copyright © {{ site.time | date: &quot;%Y&quot; }} {{ site.author }}. All rights reserved.&lt;span class=&quot;nt&quot;&gt;&amp;lt;/rights&amp;gt;&lt;/span&gt;

 {% for post in site.posts %}
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;entry&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{ post.title }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;alternate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ site.url }}{{ post.url }}&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;updated&amp;gt;&lt;/span&gt;{{ post.date | date_to_xmlschema }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/updated&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;{{ site.url }}{{ site.baseurl }}{{ post.id }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;{{ post.description }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;content&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;html&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;{{ post.content | xml_escape }}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/content&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;/entry&amp;gt;&lt;/span&gt;
 {% endfor %}

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/feed&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note on YAML Front Matter block:&lt;/strong&gt; It’s important to leave the dashes at the top of the file. This is necessary because Jekyll will not process a page with Liquid unless there is a YAML block at the top of the file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enable auto-discovery:&lt;/strong&gt; Make sure you add the appropriate meta tag to support automated discovery of your feed. Place the following code somewhere in your template’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section to output the necessary metadata:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;application/atom+xml&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;alternate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ site.url }}/feed.xml&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{{ site.title }}&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;create-the-xsl-file-to-style-the-feed&quot;&gt;Create the XSL file to style the feed&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms759096%28v=vs.85%29&quot; title=&quot;What Is XSLT?&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;We can use XSLT to style our XML&lt;/a&gt;. This makes our feeds more human-readable while supporting bots, aggregators, and search engines.&lt;/p&gt;

&lt;p&gt;You’ll notice some similarities to HTML and CSS in the example below, but with a few semantic changes and special attributes.&lt;/p&gt;

&lt;p&gt;First, you can place your CSS in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag like normal. You can also use some standard HTML markup like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;body&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;section&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;p&amp;gt;&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;

&lt;p&gt;There are a few special elements you can use, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;xsl:apply-templates&amp;gt;&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;xsl:value-of&amp;gt;&lt;/code&gt;. I won’t cover these in detail during this tutorial, but W3Schools maintains &lt;a href=&quot;https://www.w3schools.com/xml/xsl_elementref.asp&quot; title=&quot;XSLT Reference&quot;&gt;a great XSLT reference&lt;/a&gt; if you want to learn about all these special elements.&lt;/p&gt;

&lt;p&gt;This Github Gist shows an &lt;a href=&quot;https://gist.github.com/andrewstiefel/57a0a400aa2deb6c9fe18c6da4e16e0f&quot; target=&quot;blank&quot; rel=&quot;noopener noreferrer&quot;&gt;example of the XLST stylesheet I created for my website&lt;/a&gt;. I wrote some basic CSS styles to format it, but you could even tap into your site’s primary CSS file to keep the styling consistent.&lt;/p&gt;

&lt;p&gt;Save your file as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feed.xsl&lt;/code&gt; and add the tag below to your XML file. Make sure the href tag points to the correct location and file name for your website.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;?xml-stylesheet href=&quot;/feed.xsl&quot; type=&quot;text/xsl&quot;?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;With a little extra care and attention, we can improve the experience of using RSS and Atom feeds across the web. Now when you visit my feed, you are greeted with an explanation of how to get started and a formatted recap of my latest posts.&lt;/p&gt;

&lt;p&gt;I made my own XML template and XSLT stylesheet based on the examples above. You can &lt;a href=&quot;https://andrewstiefel.com/feed.xml&quot; title=&quot;Andrew Stiefel&apos;s Feed&quot; target=&quot;_blank&quot; data-fathom=&quot;RSS subscription&quot;&gt;see it in action here&lt;/a&gt; or &lt;a href=&quot;https://gist.github.com/andrewstiefel/57a0a400aa2deb6c9fe18c6da4e16e0f&quot; title=&quot;Github Gist&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;download a version&lt;/a&gt; to adapt for your website.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;h2 id=&quot;additional-reading&quot;&gt;Additional Reading&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://interconnected.org/home/2020/07/29/improving_rss&quot; title=&quot;Interconnected by Matt Webb&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;How would I improve RSS? Three ideas (Interconnected by Matt Webb)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://lepture.com/en/2019/rss-style-with-xsl&quot; title=&quot;Just Lepture&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;How to style an RSS feed (Just Lepture)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://natclark.com/tutorials/xslt-style-rss-feed/&quot; title=&quot;Nat Clark&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Styling an RSS Feed with XSLT (Nat Clark)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://aboutfeeds.com/&quot; title=&quot;About Feeds&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;About Feeds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>How I built my blog with Jekyll and Netlify</title>
   <link rel="alternate" href="https://andrewstiefel.com/blog-jekyll-netlify/"/>
   <published>2021-12-20T00:00:00-08:00</published>
   <id>https://andrewstiefel.com/blog-jekyll-netlify</id>
   <summary>I used Jekyll and Netlify to build a custom personal website and blog.</summary>
   <content type="html">&lt;p&gt;I’ve been blogging and hosting my website since 2006, but I’ve always been unhappy with the themes available for technologies like Blogger, WordPress, or Squarespace. I usually had a vision for what I wanted to create and would spend hours scouring marketplaces to find something that came close.&lt;/p&gt;

&lt;p&gt;At first, I experimented with developing child themes for WordPress. If you’re not familiar with WordPress, I basically overwrote the CSS stylesheets and built my own page and post templates using PHP. I even got good enough that I had clients who would hire me to make changes to their WordPress themes and installations.&lt;/p&gt;

&lt;p&gt;Still, all of the tweaks and changes felt cobbled together. They &lt;em&gt;were&lt;/em&gt; cobbled together. I was building Frankenstein sites with dozens of overrides, plugins, and hacks that could break at any moment.&lt;/p&gt;

&lt;h2 id=&quot;searching-for-something-better&quot;&gt;Searching for something better&lt;/h2&gt;

&lt;p&gt;I wanted to escape the bloat of platforms like WordPress, or the restricted design options available with a platform like Squarespace. &lt;strong&gt;I wanted to go back to static HTML and CSS and I wanted to code it myself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After reading online, I came across &lt;a href=&quot;https://jekyllrb.com/&quot; title=&quot;Jekyll&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Jekyll&lt;/a&gt;. It’s an open-source &lt;a href=&quot;https://www.cloudflare.com/learning/performance/static-site-generator/&quot; title=&quot;What is a static site generator?&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;static site generator&lt;/a&gt;. That means it complies basic text files into static HTML so you don’t have to code every page by hand.&lt;/p&gt;

&lt;p&gt;I built a few starter projects with Jekyll and quickly fell in love with it. While there are a variety of open-source static site generators available now, I still enjoy the relative simplicity of Jekyll for getting started. The liquid templating language is easy to understand and your HTML/CSS/JS work cleanly together.&lt;/p&gt;

&lt;p&gt;Jekyll may not be the sleekest option — there are good reasons to pick something like &lt;a href=&quot;https://www.gatsbyjs.com/&quot; title=&quot;Gatsby JS&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Gatsby&lt;/a&gt; or &lt;a href=&quot;https://nextjs.org/&quot; title=&quot;Next JS&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Next.js&lt;/a&gt; if you work with javascript and react — I still think it is the most approachable option for beginners (like me).&lt;/p&gt;

&lt;h2 id=&quot;to-use-a-cms-or-not&quot;&gt;To use a CMS or not?&lt;/h2&gt;

&lt;p&gt;I built a few starter websites with Jekyll. One of the things I missed at first was the integration with my writing tool of choice (&lt;a href=&quot;https://ulysses.app/&quot; title=&quot;Ulysses App&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Ulysses&lt;/a&gt;). I also wanted some of the benefits of a CMS, like scheduling posts. Ulysses integrates with WordPress and &lt;a href=&quot;https://ghost.org/&quot; title=&quot;Ghost&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Ghost&lt;/a&gt; so you can publish from mobile and desktop. I decided to give Ghost a try.&lt;/p&gt;

&lt;p&gt;As a CMS, I did love Ghost. It’s simple and focused on the writing experience. They have even embraced the &lt;a href=&quot;https://jamstack.org/what-is-jamstack/&quot; title=&quot;Jamstack&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Jamstack&lt;/a&gt; (Javascript, APIs, and markup) movement driving static websites and supporting headless designs. I also liked the idea of keeping my content separate from the frontend framework.&lt;/p&gt;

&lt;p&gt;I worked with Ghost for a while but kept getting frustrated with the server upkeep that it invariable entailed. At first, I paid for a monthly subscription, but the functionality at the basic level is limited unless you spend $30/mo. At that level, you can either create your own theme to host with them or use their API to support a frontend framework built with Jekyll, Gatsby, or another tool. The cost is about the same as a good WordPress hosting provider, but that was more than I was willing to spend for the convenience of scheduling posts within a CMS.&lt;/p&gt;

&lt;p&gt;I should note that Ghost also offers an option to self-host (&lt;a href=&quot;https://marketplace.digitalocean.com/apps/ghost&quot; title=&quot;Ghost App on Digital Ocean&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;starting at $5/mo through Digital Ocean&lt;/a&gt;) but I didn’t want to maintain the server myself. I already have enough reasons to not write without throwing in server updates…which were one of the reasons I wanted to leave WordPress.&lt;/p&gt;

&lt;p&gt;Ultimately, I decided to forgo the CMS and focus on Jekyll. I’ll write more about this in the future, but Jekyll fits into my growing philosophy around working with markdown for personal knowledge management and publishing.&lt;/p&gt;

&lt;h2 id=&quot;publishing-with-netlify&quot;&gt;Publishing with Netlify&lt;/h2&gt;

&lt;p&gt;My first Jekyll website was published using Github pages. While I loved the option to publish a free project website directly from my repo, it was definitely more difficult to manage and came with a host of limitations.&lt;/p&gt;

&lt;p&gt;Ultimately, I went with Netlify. They are a fantastic organization that makes it easy to build, deploy, and scale web projects. Using Jekyll, I can generate a website from my repo on Github and Netlify deploys it to edge servers across its network. Since I’m only serving static HTML files, this makes my websites incredibly fast for readers. And there is no server (on my end) to worry about securing, protecting, etc. Netlify handles the build and deploys the static files acrss the edge.&lt;/p&gt;

&lt;h2 id=&quot;getting-set-up&quot;&gt;Getting set up&lt;/h2&gt;

&lt;p&gt;I won’t go into too much detail on the development process here, but I will link to the resources that I found the most helpful for getting started:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://getpoole.com/&quot; title=&quot;Poole&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Poole: &lt;/a&gt;Clean and concise foundational setup for Jekyll&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.netlify.com/blog/2020/04/02/a-step-by-step-guide-jekyll-4.0-on-netlify/&quot; title=&quot;Netlify&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;How to deploy Jekyll with Netlify&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/creating-a-github-pages-site-with-jekyll&quot; title=&quot;Github&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;How to deploy Jekyll with GitHub pages&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://formspree.io/&quot; title=&quot;Formspree&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Formspree:&lt;/a&gt; Open-source form solution for static websites&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://shopify.github.io/liquid/&quot; title=&quot;Shopify on GitHub&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Liquid template language reference&lt;/a&gt; from Shopify&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.netlify.com/&quot; title=&quot;Netlify Docs&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Getting started with Netlify&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As one of the original static website generators, Jekyll benefits from a large community of open-source contributors and users who have documented their techniques and solutions. If you get stuck, there is most likely a tutorial with the answers you need!&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;p&gt;Overall I’m pretty happy with the results of the project. I learned a lot along the way and ended up with a website that doesn’t look too bad and is unique to me. While I don’t need to make any changes to start writing, there are a few areas I plan to explore in the coming months:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implement Tailwind CSS to replace Bulma&lt;/strong&gt;
I used the &lt;a href=&quot;https://bulma.io/&quot; title=&quot;Bulma Docs&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Bulma CSS Framework&lt;/a&gt; to scaffold the development of this project. Previously, I used Bootstrap for a few starter projects. Bulma is great, but I’ve been wanting something easier to customize. Enter &lt;a href=&quot;https://tailwindcss.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Tailwind CSS&lt;/a&gt;, which is a just-in-time, atomic framework for creating CSS. I can build and design the website, all within HTML. Then, I can filter out any unused classes, resulting in a very small file.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Update 2024-12-01:&lt;/strong&gt; I completed this work back in May 2022. I am currently using the excellent &lt;a href=&quot;https://github.com/vormwald/jekyll-tailwindcss&quot;&gt;jekyll-tailwindcss plugin&lt;/a&gt; to implement Tailwind CSS for my site. I wraps the Tailwind CSS CLI and lets you specify which version of Tailwind CSS you want to use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Buildout functionality for my digital garden&lt;/strong&gt;
I expect to write about this more in the coming months, but I’m planning to treat this blog more like &lt;a href=&quot;https://maggieappleton.com/garden-history&quot; title=&quot;A Brief History of the Digital Garden&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;a digital garden&lt;/a&gt;. There are some core functionalities I want to add, like sides notes, bi-directional links, and search, to make the reading experience more rich and interconnected.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Update 2024-12-01:&lt;/strong&gt; I’m still working on this. Overall this feels a bit more like a distraction from writing than a priority. I have played around with introducing categories for evergreen, seedling, and budding notes to indicate how complete an idea/post is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Rebuild the site with Gatsby, Next, or another framework&lt;/strong&gt;
I really like Jekyll, so this one isn’t urgent. But I’m starting to see how javascript frameworks like Gatsby, Next, or Vue could enable some new capabilities. One function that stands out to me is the ability to import markdown (my blog posts) from a separate Github repository. This way my thinking and writing could truly exist separately (and under version control!) from the frontend visual design.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Update 2024-12-01:&lt;/strong&gt; I no longer plan to do this for a variety of reasons. I may write more about why in the future, but the short version for now is that I &lt;em&gt;hate&lt;/em&gt; dependencies and heavy frameworks. I like how simple Jekyll is to run, and that the final result is really just a bunch of html files, one stylesheet, and one bit of non-critical, vanilla Javascript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope you have a similar positive experience, and please reach out if you have any questions about building your website with Jekyll and Netlify.&lt;/p&gt;

</content>
 </entry>
 

</feed>
