<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter Thaleikis 🍪</title>
    <description>The latest articles on DEV Community by Peter Thaleikis 🍪 (@spekulatius1984).</description>
    <link>https://dev.to/spekulatius1984</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F146805%2Ff46810d4-adfd-4b86-99f2-ba71f43078bd.jpg</url>
      <title>DEV Community: Peter Thaleikis 🍪</title>
      <link>https://dev.to/spekulatius1984</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/spekulatius1984"/>
    <language>en</language>
    <item>
      <title>How profitable are VPN services?</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Mon, 26 Jul 2021 21:21:58 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/how-profitable-are-vpn-services-248h</link>
      <guid>https://dev.to/spekulatius1984/how-profitable-are-vpn-services-248h</guid>
      <description>&lt;p&gt;If you ever spent an hour on YouTube, you have surely seen the greatly discounted offers of VPNs. This left me wondering, how profitable are these companies if they offer such discounts and pay for ads, commissions, etc. on top?&lt;/p&gt;

&lt;p&gt;Unfortunately, these days, your ISP has the freedom to make money from their customers not just with their internet bill. In the US, they can even sell your personal information and internet traffic to advertisers to make a profit. This has resulted in a privacy-driven interest in VPNs. The result: a booming VPN marketplace that's bringing in millions of dollars per year.&lt;/p&gt;

&lt;h2&gt;
  
  
  A look at the VPN market
&lt;/h2&gt;

&lt;p&gt;In 2021, there is a rising demand for VPN services. In fact, &lt;a href="https://thebestvpn.com/vpn-usage-statistics/"&gt;95% of Americans&lt;/a&gt; are worried about how companies are using and selling their data online, which is an 80% increase compared to the previous year. Nowadays, 50% of people are looking for new ways to ensure their data is protected.&lt;/p&gt;

&lt;p&gt;Although it could be assumed that the fear of cyber attacks and security risks would be driving the market - this isn't actually the case. 50% of people use VPNs to &lt;a href="https://thebestvpn.com/vpn-usage-statistics/"&gt;access better entertainment&lt;/a&gt; content. While only 18% use a virtual private network to &lt;a href="https://thebestvpn.com/vpn-usage-statistics/"&gt;hide internet traffic&lt;/a&gt; from the government. Localized Netflix and &lt;a href="https://whichlogin.com/facebook/temporarily-restricted-by-facebook-how-to-deal-with-facebook-jail/"&gt;blocked Facebook&lt;/a&gt; are a more motivating driver than privacy, surprisingly. As far as internet security is concerned, 51% of people have had their online accounts compromised in 2020 alone.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://thebestvpn.com/vpn-usage-statistics/"&gt;largest consumers are men&lt;/a&gt; at 62% and are generally younger than 34 years old. The number one consumer of VPNs is in the Asia Pacific region (likely due to strongly restricted Internet access in the region), harboring 30% of all VPN usage. Currently, the up and coming markets are Indonesia, India, and Turkey. Surely no coincidence.&lt;/p&gt;

&lt;p&gt;This leaves the question: how are these businesses generating profit despite their generous offers?&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost of Revenue
&lt;/h2&gt;

&lt;p&gt;In Fortinet's case, their current costs are &lt;a href="https://finance.yahoo.com/quote/FTNT/financials?p=FTNT"&gt;$597,900 TTM&lt;/a&gt; compared to the total revenue of 2.7 million dollars. Their average costs over the last four years have been $501,896 p.a. That's an average of 22% in the cost of revenue per year. In terms of profit, they have steadily gained an average of 20% in profits every year from 2017-2020. These trends show just how profitable VPN companies are becoming and how they are steadily growing into a billion-dollar industry.&lt;/p&gt;

&lt;p&gt;In the case of NortonLifeLock, there is a stark difference between the total revenue and cost of revenue. Currently, the TTM for this year is over &lt;a href="https://finance.yahoo.com/quote/NLOK/financials?p=NLOK"&gt;2.5 million dollars&lt;/a&gt;, but the cost of revenue sits at an easy $362,000. With relatively low costs of revenue in contrast to the generally high revenue, it is a lucrative and flourishing market for VPN businesses right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  High Profit Margins
&lt;/h2&gt;

&lt;p&gt;With the cost of a single active user far lower than one dollar, the profit margin for VPN services are extremely high. Each customer can bring in anywhere from $40 USD to over $100 USD per year depending on the functionality, speed, and dependability of the service. Established companies, like NordVPN, made &lt;a href="https://atlasvpn.com/blog/top-10-vpns-had-31-million-installs-ytd-generating-23m-in-revenue"&gt;7.8 million dollars in 2020&lt;/a&gt;. But NordVPN was not even the highest earning VPN service. Hotspot Shield made almost &lt;a href="https://atlasvpn.com/blog/top-10-vpns-had-31-million-installs-ytd-generating-23m-in-revenue"&gt;9 million dollars in profit&lt;/a&gt; last year with over 6.1 million mobile installs.&lt;/p&gt;

&lt;p&gt;Take a look at Fortinet, for example. They currently have a profit margin of &lt;a href="https://finance.yahoo.com/quote/FTNT/financials?p=FTNT"&gt;18.01%&lt;/a&gt;. Now, this may be in the average range, but Fortinet has a 2.02 billion gross profit for the trailing twelve months (TTM) and a 64.74% return on equity. NortonLifeLock has an even higher profit margin of &lt;a href="https://finance.yahoo.com/quote/NLOK/financials?p=NLOK"&gt;21.72%&lt;/a&gt; and current total revenue of 2.5 million dollars this year.&lt;/p&gt;

&lt;p&gt;Sounds great, doesn't it? But where is the market heading?&lt;/p&gt;

&lt;h2&gt;
  
  
  VPN Market Growth Projections
&lt;/h2&gt;

&lt;p&gt;In 2020, the VPN market grew to an unprecedented 30 billion dollars and is expected to grow even larger in the next 6 years. Projections are estimating a &lt;a href="https://www.gminsights.com/industry-analysis/virtual-private-network-vpn-market"&gt;15% CAGR increase&lt;/a&gt; by 2027. With more and more people gaining access to the internet, alongside the growing demand for corporate internet security, it's not surprising that VPN usage is on the rise. The estimated value projection for 2027 is &lt;a href="https://www.gminsights.com/industry-analysis/virtual-private-network-vpn-market"&gt;120 billion&lt;/a&gt;, a 300% increase from 2020.&lt;/p&gt;

&lt;p&gt;One of the driving forces behind this demand for businesses is a rise in cybercrime, data breaches, and better access to entertainment. The reasons behind VPN usage vary greatly between regions. The Asia Pacific, Middle East, Africa, and Latin America use virtual private networks for entertainment content. Whereas Europe and North America use a VPN for internet anonymity. But, these two factors overlap quite a bit.&lt;/p&gt;

&lt;p&gt;The majority of people believe that their online safety is in the hands of corporations and internet providers. On the other hand, 95% of businesses keep sensitive information in the cloud and &lt;a href="https://thebestvpn.com/vpn-usage-statistics/"&gt;93% of IT professionals&lt;/a&gt; have admitted that they face challenges with data safety online. All in all, the consumer is not just a single person anymore but entire corporations seeking online privacy and security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In conclusion, the VPN market is thriving all over the world due to a rise in internet penetration, local restriction of Internet access, demands for internet security, and, of course, entertainment purposes. The Virtual Private Network industry is showing no signs of slowing down. If you aren't up to operate a business, you can still benefit by investing in &lt;a href="https://www.thestockdork.com/vpn-stocks/"&gt;VPN public companies&lt;/a&gt;. This way, you make money on the rising CAGR of virtual private networks.&lt;/p&gt;

</description>
      <category>vpn</category>
      <category>business</category>
    </item>
    <item>
      <title>What license to use for private NPM/node or composer packages</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Sat, 09 Jan 2021 08:40:23 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/what-license-to-use-for-private-npm-node-or-composer-packages-3876</link>
      <guid>https://dev.to/spekulatius1984/what-license-to-use-for-private-npm-node-or-composer-packages-3876</guid>
      <description>&lt;p&gt;As much as I love open-source, not every project or package is meant to become open-source. Especially commercial projects are usually not released under an open-source license. For these cases you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Private NPM/yarn packages with a license defined as &lt;strong&gt;"UNLICENSED"&lt;/strong&gt; should do the trick. Make sure to not confuse it the "UNLICENSE", which is open-source.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Private composer packages can use the license key &lt;strong&gt;"proprietary"&lt;/strong&gt; to avoid issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. More a public note here than an article, but I guess that's fine.&lt;/p&gt;




&lt;h1&gt;
  
  
  Other articles of mine that you might like
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spekulatius.hashnode.dev/personal-discovery-journey-into-code-world-faasd-and-openfaas"&gt;Personal Discovery Journey Into Code-World: FaaSD and OpenFaaS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spekulatius.hashnode.dev/thank-me-later-how-to-install-php-ext-intl-in-docker-on-alpine-linux"&gt;Thank me later: How to install PHP ext-intl in docker on Alpine Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spekulatius.hashnode.dev/common-issues-using-laravel-websockets-with-beyondcode-laravel-websockets"&gt;Common Issues using Laravel Websockets with beyondcode/laravel-websockets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spekulatius.hashnode.dev/phpscraper-and-python3-beautifulsoup-in-comparison"&gt;PHPScraper and Python3 BeautifulSoup in Comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spekulatius.hashnode.dev/how-to-upgrade-your-node-versions-on-linux-development-machines-and-keep-up-to-date"&gt;How to Upgrade Your Node Versions on Linux Development Machines and Keep up to Date&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>PHPScraper and Python3 BeautifulSoup in Comparison</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Mon, 05 Oct 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/phpscraper-and-python3-beautifulsoup-in-comparison-3aj9</link>
      <guid>https://dev.to/spekulatius1984/phpscraper-and-python3-beautifulsoup-in-comparison-3aj9</guid>
      <description>&lt;p&gt;A while ago I found &lt;a href="https://github.com/FriendsOfPHP/Goutte"&gt;Goutte&lt;/a&gt; by the &lt;a href="https://symfony.com"&gt;Symfony Team&lt;/a&gt; on one of my &lt;a href="https://github.com/spekulatius/web-stuff"&gt;scouting missions on GitHub&lt;/a&gt;. It's a really neat library, assisting anyone scraping websites or simply processing some data coming from external websites. While working with Goutte for a bit, I noticed I abstracted parts of the functionality again and again. After building up a bunch of helpers I copied from project to project, I made a call to migrate these into a library. &lt;a href="https://github.com/spekulatius/PHPScraper"&gt;PHPScraper&lt;/a&gt; was born. It was my solution to reduce the coding overhead in PHP.&lt;/p&gt;

&lt;p&gt;I put it on GitHub, added a VuePress site as a basic documentation, and left it for the time being. Until my needs to scrape came up again. For my new project I've had to extract links with various attributes such as "target", "rel", etc. It started with some quickly put together &lt;a href="https://github.com/spekulatius/hacks"&gt;hacks&lt;/a&gt; and turned out to be an opportunity to confirm if my scraper could hold up against more advanced libraries such as Python's &lt;a href="https://www.crummy.com/software/BeautifulSoup/"&gt;BeautifulSoup&lt;/a&gt;. I've decided to build my required functionality using my limited Python knowledge and BeautifulSoup as well as PHPScraper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;Both programs needed to fulfill these requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;run as a CLI program,&lt;/li&gt;
&lt;li&gt;take an URL as argument,&lt;/li&gt;
&lt;li&gt;fetch the HTML page,&lt;/li&gt;
&lt;li&gt;extract all links with

&lt;ul&gt;
&lt;li&gt;href&lt;/li&gt;
&lt;li&gt;target&lt;/li&gt;
&lt;li&gt;rel&lt;/li&gt;
&lt;li&gt;title&lt;/li&gt;
&lt;li&gt;anchor text&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;write the result as a json to a file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fifth part is actually simplified - the data will be processed further, but for this experiment it would be sufficient to write the link-data to the filesystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping Links with Python 3 and BeautifulSoup 4
&lt;/h2&gt;

&lt;p&gt;As mentioned initially, my Python knowledge is limited and Google had to assist me here and there. The various package managers and strong differences between Python 2 and 3 made it more a little more work than anticipated. While the source code probably still could be optimized further, it fulfils the requirements. All in all, the source code is still simple and not too long:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;bs4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;urllib.request&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;

&lt;span class="c1"&gt;# Prep the request
&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'User-Agent'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Get the site
&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'utf-8'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Parse the content
&lt;/span&gt;&lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"html.parser"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="s"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'title'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;'rel'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'rel'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;'target'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'target'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;'text'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getText&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'./links.json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outfile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned, it's likely not ideal.&lt;/p&gt;

&lt;h2&gt;
  
  
  PHPScraper Link Extractor Implementation
&lt;/h2&gt;

&lt;p&gt;As mentioned above, for the PHP version, I've used my &lt;a href="https://phpscraper.de/"&gt;PHPScraper library&lt;/a&gt;. First I initialized a new composer project and then ran "composer require spekulatius/phpscraper". The source code is pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Instantiate the library&lt;/span&gt;
&lt;span class="nv"&gt;$web&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nf"&gt;spekulatius\phpscraper&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Navigate to the test page.&lt;/span&gt;
&lt;span class="nv"&gt;$web&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Extract the links&lt;/span&gt;
&lt;span class="nv"&gt;$links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$web&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;linksWithDetails&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Write the result&lt;/span&gt;
&lt;span class="nb"&gt;file_put_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'./links.json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;json_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$links&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the four functional lines code are commented, I guess it doesn't need many words here...&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Comparison: BeautifulSoup &amp;amp; PHPScraper
&lt;/h2&gt;

&lt;p&gt;Comparison of the performance is naturally hard. It depends on numerous factors, of which a large chunk is out of my control. To reduce the side effects I've opted for this test setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;tests are run on a dedicated server,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;each script gets the same 30 randomly pre-selected URLs one-by-one (see here)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;time is measured using the Linux built-in command time for the complete execution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the tests are run 5 times for each script&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this isn't the best possible test setup, it should do, to get a feeling for the performance.&lt;/p&gt;

&lt;p&gt;The test setup could be improved by e.g.,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;handing the whole list of URLs in to reduce time required to bootstrap and interpret the scripts and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;pre-fetching the HTML and handing it into the script to exclude network delays.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tests were run using the following commands:&lt;/p&gt;

&lt;p&gt;time while read url; do python3 python3-beautifulsoup-link-extractor/link-extractor.py "$url"; done &amp;lt; urls&lt;/p&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;time while read url; do php phpscraper-link-extractor/link-extractor.php "$url"; done &amp;lt; urls&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance Test Results
&lt;/h3&gt;

&lt;p&gt;As mentioned above, the test is not representative and lacks fundamentals. I've still included some numbers to indicate performance differences.&lt;/p&gt;

&lt;p&gt;The Python script with BeautifulSoup took the following time to process the url list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;21.1s&lt;/li&gt;
&lt;li&gt;19.2s&lt;/li&gt;
&lt;li&gt;16.0s&lt;/li&gt;
&lt;li&gt;14.9s&lt;/li&gt;
&lt;li&gt;16.4s&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The average being around 17.5 seconds to fetch and process the list of 30 URLs.&lt;/p&gt;

&lt;p&gt;The PHP script with PHPScraper achieved the following times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;12.4s&lt;/li&gt;
&lt;li&gt;12.7s&lt;/li&gt;
&lt;li&gt;10.4s&lt;/li&gt;
&lt;li&gt;12.6s&lt;/li&gt;
&lt;li&gt;12.1s&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The average being around 12.0 seconds to fetch and process the list of 30 URLs. This also includes processing time for additional checks for flags such as "isNofollow", etc. which hasn't been removed from the standard library.&lt;/p&gt;

&lt;p&gt;Other experiments and tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/spekulatius/phpscraper-keyword-length-distribution-example"&gt;Extracting the length distribution of keywords using PHPScraper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/spekulatius/phpscraper-keyword-scraping-example"&gt;Extracting and filtering various keyword-sets using PHPScraper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webscraping</category>
      <category>scraper</category>
      <category>beautifulsoup</category>
      <category>php</category>
    </item>
    <item>
      <title>Degoogling Your Analytics With Umami and Forge in 10 Minutes</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Sat, 03 Oct 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/degoogling-your-analytics-with-umami-and-forge-in-10-minutes-2cm6</link>
      <guid>https://dev.to/spekulatius1984/degoogling-your-analytics-with-umami-and-forge-in-10-minutes-2cm6</guid>
      <description>&lt;p&gt;Before getting into my personal solution, I want to explain my personal reasons. In short, taking control of your own data is part of keeping the web open and free. Without holding and controlling your own data, you are allowing others to use it too - for their purposes. A strong concentration on few services allows to create personal profiles about large numbers of internet users. These profiles can be used to target ads and strengthen the online bubbles people live in. This is highly undesirable as it is detrimental to our society and freedom.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Umami?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://umami.is/"&gt;Umami&lt;/a&gt; is a self-hosted analytics platform by &lt;a href="https://mikecao.com/"&gt;Mike Cao&lt;/a&gt;. It is intended to be an alternative Google Analytics (GA). Compared to GA, it comes with a much more simple user interface. It is &lt;a href="https://github.com/mikecao/umami"&gt;open-source&lt;/a&gt;, allowing anyone to inspect and modify the source code. As a Node.js application, it runs on various platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Forge?
&lt;/h2&gt;

&lt;p&gt;Next to &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;, &lt;a href="https://forge.laravel.com/"&gt;Laravel Forge&lt;/a&gt; has become my go-to solution for hosting applications. While it's built for Laravel, it's still doing a very good job in hosting other applications. For example, I've hosted &lt;a href="https://bringyourownideas.com/blog/using-laravel-forge-to-host-silverstripe-4/"&gt;SilverStripe (a PHP CMS) on Forge&lt;/a&gt; without any bigger issues.&lt;/p&gt;

&lt;p&gt;Here I'll show you the few steps required to host the Umami node application on Forge.&lt;/p&gt;

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

&lt;p&gt;To get started you need to have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;an account on GitHub,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;an account on Forge, and&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;at least one connected hosting company on Forge.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have prepared these steps, you are good to go.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Umami on Forge
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Start with creating a new server. For myself, I've been using &lt;a href="https://peterthaleikis.com/hetzner"&gt;Hetzner&lt;/a&gt;. But &lt;a href="http://peterthaleikis.com/digitalocean"&gt;Digital Ocean&lt;/a&gt; works the same way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dwoxda73--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600088981541/rJAySjlOx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dwoxda73--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600088981541/rJAySjlOx.png" alt="1-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've picked umami as a server name - to make it memorable. The other settings are the basics and should do the job.&lt;/p&gt;

&lt;p&gt;This step will provide you with two passwords. Keep them safe. You will need the MySQL password shortly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next I've configured a new sub-domain on my blog, &lt;a href="https://peterthaleikis.com/"&gt;peterthaleikis.com&lt;/a&gt;. This subdomain points to the IP assigned by Hetzner (or DO) - you can see it on your Forge dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uq6dXYLo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600088996260/J3BzvQ3hd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uq6dXYLo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600088996260/J3BzvQ3hd.png" alt="2-min.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next is setting up a new site; our new Forge-managed server:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qcrwQTVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089008422/Gb-jc5emu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qcrwQTVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089008422/Gb-jc5emu.png" alt="3-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've picked static HTML, but this isn't what the site will be at the end. With this, I've also created a new database - again, simply called "umami".&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Once the site is created, you need to install the repo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7mbko52k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089020678/pfLsRFy78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7mbko52k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089020678/pfLsRFy78.png" alt="4-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To allow Forge easy access, you will need to fork the original repo on GitHub. Your GitHub repo should then be called your-username/umami. Don't forget to remove the tick on "install computer dependencies":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g4ViDYSS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089042373/FCTlztrNi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g4ViDYSS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089042373/FCTlztrNi.png" alt="5-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will clone the repo.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go on your site and configure the environment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--31FUeo9h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089053825/zVTbvzBVg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--31FUeo9h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089053825/zVTbvzBVg.png" alt="6-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The model after clicking "Edit Environment" allows you to change your environment configuration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HLAVHHl2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089063909/qiRnMUGlh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HLAVHHl2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089063909/qiRnMUGlh.png" alt="7-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you will need to enter two lines:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL=mysql://forge:your-mysql-password@localhost:3306/umami
HASH_SALT=BxhDB2nUhYcPGVs3jH5FMBDjmh4nchZS2x
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Please replace the "your-mysql-password" string with your MySQL password from step one. Also replace the salt with some &lt;a href="https://duckduckgo.com/?q=password+30&amp;amp;t=canonical&amp;amp;atb=v35-2b_&amp;amp;ia=answer"&gt;random characters&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click over to the SSL tab and get a &lt;a href="https://letsencrypt.org/"&gt;Let's Encrypt cert&lt;/a&gt; for your new site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K_eBJXSk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089103724/9mIc63U2K.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K_eBJXSk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089103724/9mIc63U2K.png" alt="8-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This should get your connections secured and avoids "Insecure Content" issues while serving the analytics script.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next we need to change the Nginx configuration. To do so, open the "Files" menu at the bottom of your Forge project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T0c3MgIg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089113435/hxRbgNdOa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T0c3MgIg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089113435/hxRbgNdOa.png" alt="9-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update the location block marked here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--11cPaUOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089133535/HJUrj0Zsb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--11cPaUOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089133535/HJUrj0Zsb.png" alt="10-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;location / {
    proxy_pass http://localhost:3000;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And save the settings. Reload nginx with the button "Restart" next to "Files".&lt;/p&gt;

&lt;p&gt;Two more steps and you are done!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next you need to load the default database. To do this, you will need to ssh into your server or add a recipe on Forge and run it once. I've opted to ssh into the machine as it's faster:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh forge@your-ip
cd ~/your-host-name
mysql -u forge -p umami &amp;lt; sql/schema.mysql.sql
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You will be prompted for your SQL password from step one here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The final step is to set up a daemon to ensure the node application keeps running. In your server configuration under "Daemons" you can fill in the form similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZBslhM4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089192033/D6JfetV-R.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZBslhM4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089192033/D6JfetV-R.png" alt="11-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to replace the "Directory" with your directory.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nine steps might sound a lot, but the whole process is completed in a few minutes if you are reasonably fast and have a bit of experience with Forge and SSH.&lt;/p&gt;

&lt;h2&gt;
  
  
  One More Hint
&lt;/h2&gt;

&lt;p&gt;When adding your analytics code-snippet to your websites, ensure it has https instead of http as a protocol. For me it did take a bit time until Umami picked up on the new SSL cert generated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PuDce9M_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089208982/Niku7r36f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PuDce9M_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600089208982/Niku7r36f.png" alt="12-min.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the protocol hasn't updated, you can either wait a little or just manually add the "s" in your snippet.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's it!
&lt;/h2&gt;

&lt;p&gt;You are done. You can now navigate to your host and access your new Umami instance, configure sites and start your own &lt;a href="https://github.com/spekulatius/awesome-privacy-friendly-web-analytics"&gt;privacy-friendly analytics&lt;/a&gt;. If you planning to &lt;a href="https://releasecandidate.dev/how-to-delete-a-property-in-google-analytics"&gt;delete GA now&lt;/a&gt;, don't struggle through the menu as me.&lt;/p&gt;

&lt;p&gt;If you are running a VuePress site for any of your open-source projects, I've got another little thing for you: A &lt;a href="https://github.com/spekulatius/vuepress-plugin-umami"&gt;VuePress-plugin to enable Umami&lt;/a&gt;. Once I was on it, I've also created plugins for  &lt;a href="https://github.com/spekulatius/vuepress-plugin-ackee"&gt;Ackee&lt;/a&gt;  and  &lt;a href="https://github.com/spekulatius/vuepress-plugin-plausible"&gt;Plausible&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;Thanks for reading and doing something for privacy on the web! If you liked this, you might also want to consider &lt;a href="https://peterthaleikis.com/newsletter/"&gt;my newsletter 💪️ 📨️&lt;/a&gt;    &lt;/p&gt;

</description>
      <category>umami</category>
      <category>analytics</category>
      <category>privacy</category>
      <category>laravel</category>
    </item>
    <item>
      <title>How to Upgrade Your Node Versions on Linux Development Machines and Keep up to Date</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Wed, 30 Sep 2020 17:28:15 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/how-to-upgrade-your-node-versions-on-linux-development-machines-and-keep-up-to-date-5fk0</link>
      <guid>https://dev.to/spekulatius1984/how-to-upgrade-your-node-versions-on-linux-development-machines-and-keep-up-to-date-5fk0</guid>
      <description>&lt;p&gt;If you are running a Linux development (or even Mac or Windows) machine as I am, you might have noticed that your node version is quite outdated at times. The official dependency channels are usually several versions behind the latest version. Here, I show how I use NVM to keep it up to date.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to find out which version of node I'm running 
&lt;/h2&gt;

&lt;p&gt;To see which node version you are using you can simply run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;on your console. This will show you the latest version. For my machine, at the time of writing, it looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KJ0G3-Wp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/eAK7lr-BiJtC8tfKkJfPXssPU66t-c__fCbU7anH0QxdxIcSyOVlKpshp7L2yEEBTWJbnTHdI35Aw-Yn7zTdmn1kVZjvvFzpou253B3K6nvbTn7Uq_wh4rp1AJRqHOLnuPZMJhqr" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KJ0G3-Wp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/eAK7lr-BiJtC8tfKkJfPXssPU66t-c__fCbU7anH0QxdxIcSyOVlKpshp7L2yEEBTWJbnTHdI35Aw-Yn7zTdmn1kVZjvvFzpou253B3K6nvbTn7Uq_wh4rp1AJRqHOLnuPZMJhqr" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to meet: nvm
&lt;/h2&gt;

&lt;p&gt;NVM is a &lt;a href="https://github.com/nvm-sh/nvm/"&gt;version manager for node&lt;/a&gt;. It's an open-source package that allows you to switch the node version on your development machine easily without installing packages manually every time.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://github.com/nvm-sh/nvm/#installing-and-updating"&gt;install it&lt;/a&gt; easily using one of the commands on the GitHub repo.&lt;/p&gt;

&lt;p&gt;After the installation you can install node versions using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nb"&gt;install &lt;/span&gt;12.18.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and use it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm use 12.18.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Avoid bash to fall back onto the system-node
&lt;/h2&gt;

&lt;p&gt;If you are opening a new terminal, your system will automatically reload the system-installed node version. To avoid this and run automatically on the latest node version, you can instruct nvm to always use the latest stable version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nb"&gt;alias &lt;/span&gt;default node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;Ten minutes' work to install nvm can save you from constant issues and time-drain maintaining it manually. Get it done and forget about it. Also, don't forget to like this post and subscribe to my newsletter here on the blog.&lt;/p&gt;

</description>
      <category>node</category>
      <category>npm</category>
      <category>yarn</category>
    </item>
    <item>
      <title>Bash/HTML/JS is not a valid Prism.js language for eleventy-plugin-syntaxhighlight</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Sun, 20 Sep 2020 21:14:49 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/bash-html-js-is-not-a-valid-prism-js-language-for-eleventy-plugin-syntaxhighlight-52o2</link>
      <guid>https://dev.to/spekulatius1984/bash-html-js-is-not-a-valid-prism-js-language-for-eleventy-plugin-syntaxhighlight-52o2</guid>
      <description>&lt;p&gt;This is one of the small articles I wish I had found while researching a problem I encountered. So I hope it solves your issue without much fuss.&lt;/p&gt;

&lt;p&gt;If you are into the &lt;a href="https://peterthaleikis.com/posts/introduction-to-static-site-generators/"&gt;static generator&lt;/a&gt; &lt;a href="https://www.11ty.dev/"&gt;11ty&lt;/a&gt; like me you might stumble upon one of these messages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;"Bash" is not a valid Prism.js language for eleventy-plugin-syntaxhighlight&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"HTML" is not a valid Prism.js language for eleventy-plugin-syntaxhighlight&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"JS" is not a valid Prism.js language for eleventy-plugin-syntaxhighlight&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Pug" is not a valid Prism.js language for eleventy-plugin-syntaxhighlight&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prism.js is the &lt;a href="https://www.11ty.dev/docs/plugins/syntaxhighlight/"&gt;syntax highlighting library&lt;/a&gt; used in eleventy.&lt;/p&gt;

&lt;p&gt;Good news is: I've got an easy solution for you available. Change the spelling to lowercase and you should be good to go.&lt;/p&gt;

</description>
      <category>staticsitegenerator</category>
      <category>11ty</category>
      <category>eleventy</category>
      <category>prismj</category>
    </item>
    <item>
      <title>How to Delete a Property in Google Analytics</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Mon, 14 Sep 2020 12:56:05 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/how-to-delete-a-property-in-google-analytics-1662</link>
      <guid>https://dev.to/spekulatius1984/how-to-delete-a-property-in-google-analytics-1662</guid>
      <description>&lt;p&gt;Once you have opted for &lt;a href="https://github.com/spekulatius/awesome-privacy-friendly-web-analytics"&gt;privacy-friendly analytics&lt;/a&gt; or simply for a tidy-up, you might want to delete properties from your Google Analytics (GA). Below is a step-by-step guide on how to delete a site in Google Analytics.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Navigate to &lt;a href="https://analytics.google.com/analytics/web/#/"&gt;Google Analytics&lt;/a&gt;. This should automatically select your first website. Click on the admin icon in the bottom left:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qBAOuJif--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087287299/1tX1qfeQ0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qBAOuJif--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087287299/1tX1qfeQ0.png" alt="1.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the property or site to delete:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Cs5O0bj6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087307939/kqEChLZw0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Cs5O0bj6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087307939/kqEChLZw0.png" alt="2.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select "Property Settings" below the property you've just selected:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xxPQY6_I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087325983/leBqfYXvM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xxPQY6_I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087325983/leBqfYXvM.png" alt="3.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move the Google Analytics site to the rubbish bin with "Move to Rubbish Bin":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q7V2XeI5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087343279/kSefIfbiL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q7V2XeI5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087343279/kSefIfbiL.png" alt="4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And confirm the action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xmVIeJWi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087354620/R1W4iLqX7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xmVIeJWi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087354620/R1W4iLqX7.png" alt="5.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The site will finally be deleted around one month (35 days) after moving it to the rubbish bin. If you want to restore it you can do it so here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Npv82Ocs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087365592/iG9XV0afE.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Npv82Ocs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600087365592/iG9XV0afE.png" alt="6.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Done!
&lt;/h2&gt;

&lt;p&gt;A journey of a thousand miles starts with one step. In small steps to great results!&lt;/p&gt;

&lt;p&gt;I hope you are picking a privacy-friendly analytics solution and opting out of large tech tracking us!&lt;/p&gt;

&lt;p&gt;If you are undecided, here is again the &lt;a href="https://github.com/spekulatius/awesome-privacy-friendly-web-analytics"&gt;list of privacy-friendly analytics solutions&lt;/a&gt; mentioned in the intro! I've also built a few integrations for various VuePress installations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/spekulatius/vuepress-plugin-umami"&gt;Umami&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/spekulatius/vuepress-plugin-plausible"&gt;Plausible.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/spekulatius/vuepress-plugin-ackee"&gt;Ackee&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of these comes in handy, please leave a star to support my work.&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>umami</category>
      <category>googleanalytics</category>
      <category>analytics</category>
    </item>
    <item>
      <title>Launching your Startup on StartupResources.io</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Sun, 30 Aug 2020 07:20:25 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/launching-your-startup-on-startupresources-io-4c10</link>
      <guid>https://dev.to/spekulatius1984/launching-your-startup-on-startupresources-io-4c10</guid>
      <description>&lt;p&gt;&lt;a href="https://startupresources.io/"&gt;StartupResources&lt;/a&gt; is a resource site and newsletter featuring various tools which come in handy when starting an online business or website. If your site fits into any of the &lt;a href="https://startupresources.io/collections/"&gt;62(!) categories&lt;/a&gt; you've got a good chance of being included. To submit your project, start on the homepage:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HYOYR0rI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupResources.io/homepage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HYOYR0rI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupResources.io/homepage.png" alt="Homepage of StartupResources.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the "Let's get started"-button to submit your project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zttX_AHP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupResources.io/getting-started.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zttX_AHP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupResources.io/getting-started.png" alt="Getting Started on StartupResources.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The form contains six simple steps asking for the required information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name,&lt;/li&gt;
&lt;li&gt;Email,&lt;/li&gt;
&lt;li&gt;Project Name,&lt;/li&gt;
&lt;li&gt;Project URL,&lt;/li&gt;
&lt;li&gt;One collection to add your project to and&lt;/li&gt;
&lt;li&gt;A description&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fields look similar to this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cXvDQwSn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupResources.io/field-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cXvDQwSn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupResources.io/field-example.png" alt="Field Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Done! You just got your project in front of over thousands of new potential users and customers. Don't forget to signup for the neat weekly newsletter once you are on the website!&lt;/p&gt;

</description>
      <category>indiehacker</category>
      <category>startup</category>
      <category>marketing</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>My Indie Hacker Rules</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Sun, 30 Aug 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/my-indie-hacker-rules-4c3p</link>
      <guid>https://dev.to/spekulatius1984/my-indie-hacker-rules-4c3p</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fle1eaik85e8oihofdvlx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fle1eaik85e8oihofdvlx.png" alt="My Indie Hacker Rules"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes you learn some "natural" rules when you've been doing something for a while. Being an indie hacker is no different. Over time, I've identified these rules for my work on bootstrapped indie projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Projects don't need to be complicated. Check out this &lt;a href="https://www.producthunt.com/posts/newsletter-virtual-mall" rel="noopener noreferrer"&gt;one&lt;/a&gt; - it's literally a Google Sheet and a domain. If you don't need to have a complex solution don't overcomplicate it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;"I can build a better version of this in a weekend."&lt;/em&gt; never works out. I started to multiply my estimations by at least 3. For any larger unknown or new technology I can't just get out of my head, I add at least a factor one. Don't know how to do oAuth with this site? Plan another two days for reading yourself into the topic and getting it working properly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://wheretopost.email/" rel="noopener noreferrer"&gt;Marketing &amp;gt; Building&lt;/a&gt;: If I'm not willing to put at least 3-5 times the (actual!) development time into marketing, I &lt;a href="https://peterthaleikis.com/posts/side-project-ideas-up-for-grabs/" rel="noopener noreferrer"&gt;shelve the idea or give it away&lt;/a&gt;. Yes, that means &lt;em&gt;"I can build this in a weekend"&lt;/em&gt; turned already into full-time work over weeks by now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Just because I can build it and it doesn't exist, doesn't mean I have to build. There are usually &lt;a href="https://peterthaleikis.com/business-idea-validation" rel="noopener noreferrer"&gt;good reasons for it not to exist&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;"I can do this better"&lt;/em&gt; is seldom worth rebuilding weeks of work someone else already invested. Generally: None of those million-dollar-over-a-weekend stories (which will never apply to you) show any of the years learning and preparing for overnight success. I don't believe them, I don't read/watch them. Rome wasn't built in a day and so this won't be a successful project. Sure, there are exceptions - but the exception isn't doing more than showing the underlying rule.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I only do projects I can and will &lt;a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food" rel="noopener noreferrer"&gt;dogfood*&lt;/a&gt; myself. It simply doesn't make any sense to build something you aren't even using yourself. How are you going to find out if your features are really solving the problem? Plus motivation is going to fall flat in the long run until you get your first customers, if you aren't having any direct benefit from it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time to admit it: If a project isn't live when the reminder-email for the annual domain renewal arrives in my inbox, it's dead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I love to find the &lt;a href="https://startupnamecheck.com/" rel="noopener noreferrer"&gt;right name and snap up the domains&lt;/a&gt; quickly. I've even &lt;strong&gt;made&lt;/strong&gt; a project for exactly this! But I have to put on the brakes: No new domains until the old ones are put to use! #DomainersAnonymous&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Non-stop work isn't good. I need to go out frequently and ensure I actually move more than just going to the kitchen and getting another coffee.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Producing &amp;gt; Consuming: I get it, the Internet is a place full of shiny stuff with something for everyone. But let's be honest: consuming doesn't help in getting anything out of the door. It starts with the latest news/controversy/products/analytics or search console stats/growth-hacking ideas/________ - you name it. It also doesn't stop with the current live-stream of SpaceX launching again or with simply watching YouTube passively while coding - all of these are &lt;a href="https://peterthaleikis.com/posts/how-i-force-myself-to-work/" rel="noopener noreferrer"&gt;distracting you from achieving your goals&lt;/a&gt;. Sounds tough? Yeah, maybe, but I can't do any of these and be actually productive.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thinking "Yeah, but ....."? I'm not saying I never watch YouTube or register a domain in overboiling excitement for a &lt;a href="https://peterthaleikis.com/tags/side-projects/" rel="noopener noreferrer"&gt;new side-project&lt;/a&gt;. These are just my personal rules I &lt;em&gt;try&lt;/em&gt; to live by. That's all 👍️&lt;/p&gt;

&lt;p&gt;If you're interested in what I would consider &lt;a href="https://peterthaleikis.com/posts/what-makes-a-good-indie-hacker/" rel="noopener noreferrer"&gt;&lt;em&gt;good&lt;/em&gt; characteristics for IndieHackers&lt;/a&gt;, I wrote about this too.&lt;/p&gt;

&lt;p&gt;* = actually cookies. In case you are scrolling up to find the asterisk: it's on number six.&lt;/p&gt;

</description>
      <category>indiehacker</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>How to launch on StartupLister</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Thu, 27 Aug 2020 08:49:22 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/how-to-launch-on-startuplister-1j8b</link>
      <guid>https://dev.to/spekulatius1984/how-to-launch-on-startuplister-1j8b</guid>
      <description>&lt;p&gt;It's time for another newsletter on how to submit your project! This time we are looking at &lt;a href="https://startuplister.com/"&gt;startuplister.com&lt;/a&gt; - a site for discovering new startups and side-projects. As you will see, getting listed is very simple and painless. Let's get your project listed on Startuplister:&lt;/p&gt;

&lt;h2&gt;
  
  
  Registration
&lt;/h2&gt;

&lt;p&gt;As on many sites, you will need to register first. Click the register link in the top right corner:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pr6Y76t9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/step-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pr6Y76t9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/step-1.png" alt="StartupLister Step 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is done with basic information only: an email address and a password are enough. It's all done in just one form. Quick and easy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DeZNMIhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/step-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DeZNMIhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/step-2.png" alt="StartupLister Step 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Submitting your Startup
&lt;/h2&gt;

&lt;p&gt;Putting your startup in the race is almost as easy as registering. One form with some basic information is enough:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8hmDAK6J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/step-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8hmDAK6J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/step-3.png" alt="StartupLister Step 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you see, you'll need only:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the startup/project name&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the URL to your startup/project&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a tag-line (maximum 50 characters)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and an icon (300x300 pixel or larger)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Twitter handle is optional.&lt;/p&gt;

&lt;p&gt;Please note: You should check your submission before clicking on the 'List it' button. There seems to be no option to edit an entry!&lt;/p&gt;

&lt;h2&gt;
  
  
  Once again: Done!
&lt;/h2&gt;

&lt;p&gt;Your listing should be on the homepage now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LX_JvC6k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/listing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LX_JvC6k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://wheretopost.email/images/StartupLister.com/listing.png" alt="StartupLister Listing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't forget to upvote a few interesting projects once you are there! Indie hackers are always happy to receive support! Talking about support, if you are keen you can &lt;a href="https://www.buymeacoffee.com/spekulatius"&gt;support me with a cookie&lt;/a&gt; 🍪️&lt;/p&gt;

&lt;p&gt;If Google directed you here you should also have a look at the main sites to launch: &lt;a href="https://wheretopost.email/submit/launching-on-producthunt.html"&gt;ProductHunt&lt;/a&gt; and &lt;a href="https://wheretopost.email/submit/marketing-on-reddit.html"&gt;Reddit&lt;/a&gt;. Both can send a significant amount of traffic your way.&lt;/p&gt;

</description>
      <category>indiehacker</category>
      <category>sideprojects</category>
      <category>startup</category>
    </item>
    <item>
      <title>Submitting your Project to Publicly</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Thu, 27 Aug 2020 08:36:06 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/submitting-your-project-to-publicly-1hfk</link>
      <guid>https://dev.to/spekulatius1984/submitting-your-project-to-publicly-1hfk</guid>
      <description>&lt;p&gt;&lt;a href="https://www.publicly.io/" rel="noopener noreferrer"&gt;Publicly.io&lt;/a&gt; is a project by the well-known makers &lt;a href="https://twitter.com/mubashariqbal" rel="noopener noreferrer"&gt;Mubashar Iqbal&lt;/a&gt; and &lt;a href="https://twitter.com/danielkempe" rel="noopener noreferrer"&gt;Daniel Kempe&lt;/a&gt;. It was built as part of a hackathon in 2017. While the site isn't overly active, it provides you an easy way to submit your project. Let's get your project submitted:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fhomepage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fhomepage.png" alt="Homepage of Publicly"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After signing up using your Twitter login you come to your new timeline. This looks rather empty by default as you don't follow any projects. You can discover projects under "Projects".&lt;/p&gt;

&lt;h2&gt;
  
  
  Submitting to Publicly
&lt;/h2&gt;

&lt;p&gt;You can get started submitting your project using the button on the dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fafter-signup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fafter-signup.png" alt="After Signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This leads you to a form with two sections for basic project information and social media handles:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fform1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fform1.png" alt="Submit Form #1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fform2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwheretopost.email%2Fimages%2FPublicly.io%2Fform2.png" alt="Submit Form #2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Directly after submitting the form you will have received a new backlink for your project! All in a few minutes only. If you are on the hunt for more backlinking opportunities check out &lt;a href="https://wheretopost.email/submit/launching-on-owwly.html" rel="noopener noreferrer"&gt;Owwly&lt;/a&gt;, &lt;a href="https://wheretopost.email/submit/launching-on-sideprojects.net.html" rel="noopener noreferrer"&gt;SideProjects.net&lt;/a&gt;, &lt;a href="https://wheretopost.email/submit/launching-on-sideprojectors.com.html" rel="noopener noreferrer"&gt;SideProjectors.com&lt;/a&gt; and &lt;a href="https://wheretopost.email/submit/launching-on-yourstack.html" rel="noopener noreferrer"&gt;YourStack&lt;/a&gt; for quick wins.&lt;/p&gt;

</description>
      <category>indiehacker</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>What makes a good Indie Hacker</title>
      <dc:creator>Peter Thaleikis 🍪</dc:creator>
      <pubDate>Sun, 23 Aug 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/spekulatius1984/what-makes-a-good-indie-hacker-3hj9</link>
      <guid>https://dev.to/spekulatius1984/what-makes-a-good-indie-hacker-3hj9</guid>
      <description>&lt;p&gt;&lt;a href="https://mccormick.cx/"&gt;Chris McCormick (chr15m)&lt;/a&gt; recently announced on Indie Hackers: &lt;a href="https://www.indiehackers.com/post/holy-heck-this-is-hard-8ebe864174"&gt;"Holy heck this is hard"&lt;/a&gt; - and rightly so.&lt;/p&gt;

&lt;p&gt;Being an indie hacker isn't as simple and easy as it's often presented online. It's not just putting a little MVP together over the weekend, &lt;a href="https://wheretopost.email/kb/submit/launching-on-producthunt.html"&gt;submitting it in on ProductHunt&lt;/a&gt; and getting the cash flowing. It's mostly hard work without knowing if you'll end up with a winning product or not. It's having countless &lt;a href="https://peterthaleikis.com/business-idea-validation/"&gt;doubts about your idea&lt;/a&gt;, how to market it and the product itself.&lt;/p&gt;

&lt;p&gt;But it's doable and there are people who "win the indie hacker lottery" (lottery is a horrible word for it, btw). There are people building independent business without any external funding or other support every day. In fact, it is more common than CV funded businesses. I'm following stories and reading (too many) books about them. You rarely find them in the places you would expect - it's the little shop owner down the street and the friendly hostel you stayed at on your trip last year. Over time, I've come to see repetitive characteristics and behaviours which seem to enable success. Here are some of the qualities which make it easier (not easy) to be an indie hacker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Being Scrappy
&lt;/h2&gt;

&lt;p&gt;Without VC funding, a complete team or for that matter any resource in abundance, you naturally have to get creative when it comes to solving problems. You can't give work to employees if you can't afford any and outsourcing much of your work isn't going to be much of an option until you have a stable revenue stream at least. You will need to come up with solutions for problems which make do with what you've already got. Mostly this means you have work within your skill set and time limitations.&lt;/p&gt;

&lt;p&gt;This doesn't mean you do everything yourself though. For example, learning to develop mobile apps simply for one project isn't an efficient use of time in most cases - it would rather make sense to find a no-code builder for mobile apps to build a prototype. After the prototype has validated the idea and proved your market, it's time to consider finding a developer as a code founder or contractor - all to get to the goal with your existing skills and resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Focus
&lt;/h2&gt;

&lt;p&gt;Large and externally-funded businesses usually have to split their focus between their goals and plans and the interests of the investors. For VC-founded companies, this often raises the question of aiming for growth or profit. As Paul Jarvis noted in "&lt;a href="https://www.goodreads.com/en/book/show/37570605-company-of-one"&gt;Company of One&lt;/a&gt;", doing both at the same time is incredibly hard and you have to make a call. You need to either align your goals or find a middle ground - which both take time and energy.&lt;/p&gt;

&lt;p&gt;As a super-small just-you business, you've got only one primary goal: turning a profit to make your business sustainable. Nothing more or less. Great growth stories have to wait until you've had a chance to establish your business and ensure you've got a revenue stream to finance from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed
&lt;/h2&gt;

&lt;p&gt;One aspect indie hackers have a unique advantage in is speed. As a solo-founder, you can change your product and add features at a speed no team could. You have no planning meetings to attend, no communications with team members, and of course no handovers between team members. All these save valuable time when it comes to delivering.&lt;/p&gt;

&lt;p&gt;Further enabling your speedy turnarounds, you have in-depth knowledge of your product which allows you to deliver faster even than a team of numerous developers, designers and managers together can achieve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Innovation
&lt;/h2&gt;

&lt;p&gt;Innovating is at the core of building an indie business. Without innovation you have to compete on price and price competition usually doesn't leave much in regards to profits. Only large and on-going investments make growth viable in industries facing strong pricing-competition. Not a space for indie hackers really.&lt;/p&gt;

&lt;p&gt;But innovation comes at a price: Research and development doesn't come for free and has inherently higher risks compared to doing the same over and over again. Risks aren't what larger organisations want: after all, they usually have strong established interests of stakeholders and investors.&lt;/p&gt;

&lt;p&gt;Indie Hackers have the freedom to take risks that aren't acceptable for established companies. You can experiment with a level of freedom which is unique. Use it wisely and find the unique ways to drive customers and profitability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connection
&lt;/h2&gt;

&lt;p&gt;Unique and authentic connections are an aspect no larger company can even achieve. You are one on one without customers, every time and every day. You have the chance to stand out by being authentic and create in a way people seek it, especially online.&lt;/p&gt;

&lt;p&gt;Once a company reaches a certain size and there are dedicated roles, authentic connection is naturally harder, especially with pressure to squeeze out the last bit of growth or profit. So skip formality and bring personality to the table as long as you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this tell us?
&lt;/h2&gt;

&lt;p&gt;Yes, being an indie hacker is hard, no doubt. But it is worth bringing it into perspective before the Internet, it was much much harder and just 15 years ago pre-Stripe, pre-AWS and pre-GitHub it was much harder than today. I'm not even talking about the computing power in your pocket exceeding the Apollo Missions navigation computers. And there is also the human aspect of it: If it was easy, everyone would do it. It needs to challenge us, otherwise we wouldn't consider it worthy to achieve.&lt;/p&gt;

&lt;p&gt;Btw, if you are interested in thoughts like these you might also like to get &lt;a href="https://buttondown.email/spekulatius"&gt;my newsletter&lt;/a&gt;. Just an idea 💪️&lt;/p&gt;

</description>
      <category>indiehacker</category>
      <category>indieprojects</category>
      <category>learning</category>
      <category>bootstraping</category>
    </item>
  </channel>
</rss>
