<?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: Oleksii Antoniuk</title>
    <description>The latest articles on DEV Community by Oleksii Antoniuk (@alantalex).</description>
    <link>https://dev.to/alantalex</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%2F3865097%2Fe7eea4ef-83e8-438a-9701-865091bf4ec7.jpeg</url>
      <title>DEV Community: Oleksii Antoniuk</title>
      <link>https://dev.to/alantalex</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alantalex"/>
    <language>en</language>
    <item>
      <title>How I Built My Own Laravel Analytics Package (and Almost Didn't Crash Production)</title>
      <dc:creator>Oleksii Antoniuk</dc:creator>
      <pubDate>Thu, 21 May 2026 21:56:48 +0000</pubDate>
      <link>https://dev.to/alantalex/how-i-built-my-own-laravel-analytics-package-and-almost-didnt-crash-production-l75</link>
      <guid>https://dev.to/alantalex/how-i-built-my-own-laravel-analytics-package-and-almost-didnt-crash-production-l75</guid>
      <description>&lt;h2&gt;
  
  
  Why Not Google Analytics? (Or why I love reinventing the wheel)
&lt;/h2&gt;

&lt;p&gt;To be honest, this wasn't an easy call. I’ve been in development for quite a while and had grown accustomed to GA. What could be simpler: you slap a script with your ID onto the site, and data starts flowing into the analytics console. All that's left is to wait for the traffic to roll in and then analyze it by country, gender, age groups, and so on.&lt;/p&gt;

&lt;p&gt;Yes, that’s how it used to be, but in today’s reality, there are objective reasons to rethink this concept. Let’s be real: hooking up Google Analytics in 2026 is like putting a massive deadbolt on your front door but leaving the keys with your neighbor. Everything seems under control, but the neighbor knows exactly when you came home, what you bought, and why you have a long face. And when someone visits you and wants to stay incognito, the neighbor won't give them the keys, and they won't even tell you they stopped by. Their response would be something like: “Nobody came, I never sleep, everything is under control…”. What am I getting at?&lt;/p&gt;

&lt;h3&gt;
  
  
  Remember the General Data Protection Regulation (GDPR)?
&lt;/h3&gt;

&lt;p&gt;Now, for your analytics to work, you must display a cookie consent banner and get the user's permission. And that’s where the problem lies. 90% of users don’t accept all cookies—only the strictly necessary ones. And what does that mean? Google Analytics ends up dead in the water. Besides, everyone is sick and tired of these banners. So, if there’s a legal way to ditch them, why not take it?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(To learn how to avoid legal trouble with data protection laws, check out the article &lt;a href="https://oleant.dev/en/blog/gdpr-without-the-headache-a-guide-for-web-developers-in-germany" rel="noopener noreferrer"&gt;GDPR Without the Headache: A Guide for Web Developers in Germany &lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The decision to drop GA was made. When I decided to hit the "Eject" button and catapult myself out of the Google ecosystem, I faced a logical question: what would fill the void? Because I still needed the numbers. I started looking at the heavy artillery.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The first candidate was Matomo (formerly Piwik):&lt;/em&gt; Probably the most powerful all-in-one machine. It’s like keeping a pet elephant in your backyard. It does everything, the database grows like crazy, but it requires a separate PHP server, MySQL, and constant babysitting. For my small pet projects, it felt like trying to drive nails with a microscope.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The second tool I looked at was Plausible / Fathom:&lt;/em&gt; Sleek, modern, and privacy-respecting. But there’s a catch: you either pay a subscription (a questionable investment for a free tool) or you mess around with self-hosted Docker versions, which also eat up a good chunk of your VPS RAM.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I looked at all of this and thought: “Do I really need to spin up an entire infrastructure just to know that 50 people read my article on German taxes yesterday?”. That’s when it hit me: I don’t need a "combine harvester." I need a tiny, precision scalpel that lives right inside my Laravel application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wanted something of my own: lightweight, like a morning espresso, and not asking annoying questions about GDPR. Plus, I was simply curious about who all these people (and bots) were "knocking" on my security tools at &lt;a href="https://oleant.net" rel="noopener noreferrer"&gt;oleant.net&lt;/a&gt;. Since this blog also needed the same tool, I decided to develop a standalone package that could be easily installed via composer and published openly on Packagist.&lt;/p&gt;

&lt;p&gt;For those interested in diving into the code, the package is called &lt;strong&gt;&lt;code&gt;oleant/laravel-visit-analytics&lt;/code&gt;&lt;/strong&gt;, compatible with Laravel versions 10/11/12. GitHub link: &lt;a href="https://github.com/Oleant-NET/laravel-visit-analytics" rel="noopener noreferrer"&gt;https://github.com/Oleant-NET/laravel-visit-analytics&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Heart of the System: Middleware and the Magic of the Aftertaste
&lt;/h3&gt;

&lt;p&gt;Which architecture to use? There are various ways to implement this. Fortunately, Laravel has a great Middleware mechanism. I decided to stick with that, but would it slow down the user? They shouldn't have to care about my overhead. And what if the database goes down or something goes wrong? A 500 error page as the face of the site is definitely not what I was aiming for.&lt;/p&gt;

&lt;p&gt;That’s why a crucial decision was made — to use the &lt;strong&gt;&lt;code&gt;terminate()&lt;/code&gt;&lt;/strong&gt; method. In a Laravel Middleware, it’s like a polite waiter: he brings you the check and smiles (the &lt;strong&gt;&lt;code&gt;handle()&lt;/code&gt;&lt;/strong&gt; method), and only after you’ve already left the restaurant does he go back to wipe the table and log the tip (the &lt;strong&gt;&lt;code&gt;terminate()&lt;/code&gt;&lt;/strong&gt; method).&lt;/p&gt;

&lt;p&gt;The user has already received their page and is happy, while our server quietly and without rush writes the logs to the database in that moment. Even if something goes wrong, the client still leaves satisfied, and the waiter... just doesn't get a tip this time. Just kidding, but here’s how it works in practice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PHP&lt;/strong&gt;&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Logic to exclude non-target clients, like Admin etc.&lt;/span&gt;
        &lt;span class="c1"&gt;// …&lt;/span&gt;
        &lt;span class="c1"&gt;// Next, write our visitors to the database&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;logVisit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Throwable&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// If the DB takes a nap, we won't wake the user with a 500 error&lt;/span&gt;
        &lt;span class="nc"&gt;\Log&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Analytics failed, but we're keeping our cool: "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Lifehack&lt;/strong&gt;: All analytics code must be wrapped in a try-catch. Believe me, there's nothing sillier than "crashing" an entire project just because the logger didn't have enough room for a long User-Agent or some other non-obvious case.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GDPR on the Fly&lt;/strong&gt;: How Not to Become Public Enemy No. 1&lt;br&gt;
To avoid slapping a banner the size of half the screen saying “We are watching you, bro,” I implemented IP anonymization. We simply trim the last part of the address before it ever touches the database. This anonymizes the user and fully complies with the law. Yet, we can still tell which country, data center, etc., the visit came from. We’ll talk more about data center bots once there's more data to show.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Back to IP anonymization:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PHP&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Before: 192.168.1.154 -&amp;gt; After: 192.168.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s like seeing a crowd in masks: you understand that 5 people showed up, but who among them is your neighbor — you have no clue. The law is satisfied, and so is my conscience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payload:&lt;/strong&gt; Gathering Only the Goodies&lt;br&gt;
Initially, I wanted to write everything that comes in the URL to the database. But then I looked at the Livewire logs, where half the state of the planet is passed in the parameters, and realized — the database would explode. So, I decided to implement filtering based on allowed parameters in the config using &lt;strong&gt;&lt;code&gt;array_intersect_key&lt;/code&gt;&lt;/strong&gt;. Now, only what I’ve personally authorized in the config ends up in the logs. Clean, orderly, and zero fluff.&lt;/p&gt;

&lt;p&gt;The default set in the package config looks like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PHP&lt;/strong&gt;&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="s1"&gt;'whitelist'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'utm_source'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'utm_medium'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'utm_campaign'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'utm_term'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'utm_content'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'ref'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you can, of course, change it by publishing the config in your project first:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bash&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan vendor:publish &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"visit-analytics-config"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, a visit-analytics.php file will appear in your config folder. There, you can not only expand the list of tracked parameters (for example, adding something like page or search) but also specify excluded paths so you don't turn your database into a dump for admin panel or technical endpoint logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;The package started humming, and the data began to flow. I closed my laptop and went to bed, thinking I’d wake up to some visitor charts from a couple of friends. But reality turned out to be much tougher (and more interesting).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the next episode, we’ll step through the "looking glass": who are Palo Alto Networks, why do bots read my Terms of Service in 7 seconds, and why Linux + DuckDuckGo is a badge of quality for a visitor?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>privacy</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why I don’t trust my own deployments (and why you should audit your Security Headers)</title>
      <dc:creator>Oleksii Antoniuk</dc:creator>
      <pubDate>Sat, 11 Apr 2026 07:15:18 +0000</pubDate>
      <link>https://dev.to/alantalex/why-i-dont-trust-my-own-deployments-and-why-you-should-audit-your-security-headers-19cm</link>
      <guid>https://dev.to/alantalex/why-i-dont-trust-my-own-deployments-and-why-you-should-audit-your-security-headers-19cm</guid>
      <description>&lt;p&gt;As a Laravel developer, I’ve always felt pretty safe. Modern frameworks do a lot of heavy lifting, but here’s the cold truth: even the most secure backend can be undermined by a "leaky" frontend or a misconfigured Nginx.&lt;/p&gt;

&lt;p&gt;I caught myself constantly jumping between third-party tools every time I deployed a new feature just to make sure I hadn't messed up my Strict-Transport-Security or broken my Content-Security-Policy. Eventually, I got tired of the routine and built my own module within Oleant.&lt;/p&gt;

&lt;p&gt;What’s the deal?&lt;br&gt;
I’m talking about the Security Headers Audit. It’s not just another tool that says "everything is bad"; it breaks down exactly what's happening under the hood of your URL.&lt;/p&gt;

&lt;p&gt;Why it matters (The Tech Side):&lt;br&gt;
A lot of devs think SSL/TLS is the finish line. But without the right headers, you're still vulnerable to:&lt;/p&gt;

&lt;p&gt;Clickjacking (lack of X-Frame-Options).&lt;/p&gt;

&lt;p&gt;MIME-sniffing (no X-Content-Type-Options).&lt;/p&gt;

&lt;p&gt;XSS attacks that a solid CSP could have neutralized instantly.&lt;/p&gt;

&lt;p&gt;My Implementation:&lt;br&gt;
I built this using Laravel 11 + Inertia.js + Vue 3. This stack allowed me to make the audit process incredibly snappy. You drop the URL, and the Vue component reactively renders the status of every critical header.&lt;/p&gt;

&lt;p&gt;Give it a spin:&lt;br&gt;
I’ve exposed this tool as a dedicated route here:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://oleant.net/security-tools/headers-audit" rel="noopener noreferrer"&gt;https://oleant.net/security-tools/headers-audit&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s not a bloated "all-in-one" suite — it’s a precision scalpel. If you’re deploying something today, just throw your link in there and see how much "red" pops up. I actually found a few embarrassing gaps in my own older projects this way.&lt;/p&gt;

&lt;p&gt;Follow my journey: &lt;a href="https://oleant.dev/en/blog" rel="noopener noreferrer"&gt;https://oleant.dev/en/blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>laravel</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stop guessing, start auditing: Why I built a custom Web Performance tool for Laravel devs</title>
      <dc:creator>Oleksii Antoniuk</dc:creator>
      <pubDate>Tue, 07 Apr 2026 06:57:31 +0000</pubDate>
      <link>https://dev.to/alantalex/stop-guessing-start-auditing-why-i-built-a-custom-web-performance-tool-for-laravel-devs-5h6o</link>
      <guid>https://dev.to/alantalex/stop-guessing-start-auditing-why-i-built-a-custom-web-performance-tool-for-laravel-devs-5h6o</guid>
      <description>&lt;p&gt;Hi DEV community! 👋 &lt;/p&gt;

&lt;p&gt;As a Senior Laravel Developer, I've always been obsessed with one thing: &lt;strong&gt;Performance.&lt;/strong&gt; We all use Lighthouse and PageSpeed Insights, but I felt something was missing—a tool that speaks the language of developers and gives actionable SEO insights without the fluff.&lt;/p&gt;

&lt;p&gt;That's why I started building &lt;a href="https://oleant.net" rel="noopener noreferrer"&gt;oleant.net&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  What’s the goal?
&lt;/h3&gt;

&lt;p&gt;My mission is to simplify &lt;strong&gt;Core Web Vitals&lt;/strong&gt; optimization. It's not just about the score; it's about the user experience and how search engines perceive your architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I'm sharing here:
&lt;/h3&gt;

&lt;p&gt;On this profile and my technical blog at &lt;a href="https://oleant.dev" rel="noopener noreferrer"&gt;oleant.dev&lt;/a&gt;, I’ll be deep-diving into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advanced Laravel optimization techniques.&lt;/li&gt;
&lt;li&gt;Real-world Core Web Vitals case studies.&lt;/li&gt;
&lt;li&gt;Building high-performance SEO tools from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd love to hear your thoughts! What's your biggest struggle when it comes to web performance?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check out the auditor here:&lt;/strong&gt; &lt;a href="https://oleant.net" rel="noopener noreferrer"&gt;oleant.net&lt;/a&gt; 🚀&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>performance</category>
      <category>webdev</category>
      <category>seo</category>
    </item>
  </channel>
</rss>
