<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Benjamin Piouffle · Blog</title><description>Articles by Benjamin Piouffle</description><link>https://benjamin.piouffle.com/</link><language>en-us</language><atom:link href="https://benjamin.piouffle.com/rss.xml" rel="self" type="application/rss+xml"/><image><url>https://benjamin.piouffle.com/_astro/benjaminpiouffle.DiBNUQgw_1yJNTF.jpg</url><title>Benjamin Piouffle</title><link>https://benjamin.piouffle.com/</link><width>144</width><height>144</height></image><atom:icon>https://benjamin.piouffle.com/_astro/benjaminpiouffle.DiBNUQgw_1yJNTF.jpg</atom:icon><item><title>My burner email blocklist blocked me</title><link>https://benjamin.piouffle.com/blog/burner-email-blocklists/</link><guid isPermaLink="true">https://benjamin.piouffle.com/blog/burner-email-blocklists/</guid><description>Blocking disposable email domains at signup increasingly punishes privacy-conscious users while doing little against motivated abusers.</description><pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A few days ago I tried to sign up for a public open-data service (&lt;em&gt;the &lt;a href=&quot;https://www.ecmwf.int&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;ECMWF&lt;/a&gt;, if you care&lt;/em&gt;) using a Proton Mail alias, and the form rejected my address as “potential spam”. My frustration was mixed with a bit of guilt: in 2018 I published &lt;a href=&quot;https://github.com/Betree/burnex&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Burnex&lt;/a&gt;, an Elixir package that compared emails against a large list of known burner domains, temporary inboxes like &lt;em&gt;yopmail.fr&lt;/em&gt; that exist to receive a confirmation link and disappear. The library itself was relying on the fairly popular &lt;a href=&quot;https://github.com/wesbos/burner-email-providers&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;wesbos/burner-email-providers&lt;/a&gt; list.&lt;/p&gt;
&lt;p&gt;At the time, I was working on a collaborative fact-checking platform where account authenticity mattered, and we needed some confidence that users were not fake or batch-generated. A domain blocklist felt like a cheap heuristic for a broader trust problem.&lt;/p&gt;
&lt;p&gt;I may be late to the party, but let me put it clearly: &lt;strong&gt;I no longer recommend systematically blocking burner domains at signup.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TLDR;&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are deciding signup policy today, do not automatically reject users for using privacy email services. Distinguish between public shared inboxes and personal aliases, and only block the former. The person behind an alias is more likely protecting themselves than trying to scam you, and the spammers have already moved on. If you maintain or consume a blocklist, consider splitting the categories and encourage good practices in your documentation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;burners-and-aliases-are-not-the-same-thing&quot;&gt;Burners and aliases are not the same thing&lt;/h2&gt;
&lt;p&gt;A distinction that we often forget when it comes to email blocklists: a classic &lt;em&gt;burner email&lt;/em&gt; is a &lt;strong&gt;public&lt;/strong&gt;, short-lived inbox anyone can access, useful for clicking a verification link once and walking away. An &lt;em&gt;email alias&lt;/em&gt; is the opposite: a permanent forwarding address tied to &lt;em&gt;your&lt;/em&gt; account, that you control, can disable, and can trace back to a specific signup when your password appears in a breach.&lt;/p&gt;
&lt;p&gt;Nowadays, tools like &lt;a href=&quot;https://relay.firefox.com/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Firefox Relay&lt;/a&gt; and &lt;a href=&quot;https://support.apple.com/en-us/102648&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Apple Hide My Email&lt;/a&gt; are mainstream products, not edge-case hacker tools. Mozilla markets Relay as a way to keep your identity private when signing up for new accounts, and Apple sells Hide My Email as a way to share an address without sharing your real one (&lt;em&gt;though they may be &lt;a href=&quot;https://news.ycombinator.com/item?id=48744606&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;overselling&lt;/a&gt; that promise&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Blocklists that treat alias providers like throwaway inboxes end up blocking people who are trying to protect themselves. That matters beyond signup friction: aliases limit cross-site tracking, reduce spam after breaches, and let you know exactly which service leaked your address when junk mail starts arriving at a forwarding address you gave only to them. We should want more people using aliases, not fewer.&lt;/p&gt;
&lt;h2 id=&quot;blocklists-dont-stop-determined-abusers&quot;&gt;Blocklists don’t stop determined abusers&lt;/h2&gt;
&lt;p&gt;Determined abusers have never been limited to blocklisted domains. Gmail’s &lt;code&gt;+&lt;/code&gt; aliasing creates unlimited variations of the same inbox (&lt;code&gt;you+shop@gmail.com&lt;/code&gt;, &lt;code&gt;you+news@gmail.com&lt;/code&gt;), services like &lt;a href=&quot;https://www.emailnator.com/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Emailnator&lt;/a&gt; can help you generate infinite variations of these throwaway Gmail addresses on demand. Custom domains cost a few dollars a year while looking indistinguishable from legitimate business email. Unlike your users, spammers have the means and the time to work around a domain blocklist. For them it is a small obstacle, not a wall.&lt;/p&gt;
&lt;p&gt;Yes, blocklists still catch some low-effort automated signups. &lt;strong&gt;But the cost is asymmetric: a naive bot gets slowed down slightly, while a real user with a legit alias gets hard-rejected with no recourse.&lt;/strong&gt; You are optimizing for the attacker who gives up easily and punishing the user who takes privacy seriously. The people blocklists were meant to stop were never really stopped; they just learned to use domains you trust.&lt;/p&gt;
&lt;p&gt;Beyond blocklists, email verification in general (including confirmation links) should not be treated as proof that an account is real, unique, or trustworthy. It only proves that someone could receive an email at that address once.&lt;/p&gt;
&lt;h2 id=&quot;there-are-still-valid-uses&quot;&gt;There are still valid uses&lt;/h2&gt;
&lt;p&gt;Checking whether an email domain appears on a known-disposable list is still a reasonable signal to feed into a broader trust or risk score, to surface suspicious patterns across a batch of signups, or to ignore them in your marketing campaigns.&lt;/p&gt;
&lt;p&gt;If I were to rebuild Burnex today, I would narrow its scope to genuinely public and shared inboxes (addresses like &lt;em&gt;mailinator.com&lt;/em&gt; where anyone can receive your verification email) rather than conflating those with personal forwarding services that happen to use a non-mainstream domain:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Public burner inbox, probably ok to block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Burnex&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;is_burner?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;random@yopmail.fr&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Personal alias, usually not ok to block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Burnex&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;is_alias?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;random@passmail.net&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the problem is not just how one library categorizes domains: the upstream list Burnex relied on (&lt;a href=&quot;https://github.com/wesbos/burner-email-providers&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;wesbos/burner-email-providers&lt;/a&gt;) is consumed as-is by signup validators, third-party packages, and APIs worldwide. Many integrators block every domain in &lt;code&gt;emails.txt&lt;/code&gt; without curating it, so the list’s categorization choices have real downstream effects.&lt;/p&gt;
&lt;h2 id=&quot;for-those-who-come-after&quot;&gt;&lt;em&gt;For those who come after&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;I have opened &lt;a href=&quot;https://github.com/wesbos/burner-email-providers/issues/538&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;an issue&lt;/a&gt; to propose exactly that split in wesbos’ list: keep one file for public shared inboxes (&lt;em&gt;yopmail.fr&lt;/em&gt;, &lt;em&gt;mailinator.com&lt;/em&gt;, and similar) and add a second for personal alias and forwarding providers (&lt;em&gt;passmail.net&lt;/em&gt;, &lt;em&gt;anonaddy.me&lt;/em&gt;, &lt;em&gt;mozmail.com&lt;/em&gt;, and the rest). Then update the README with recommendations for good practices.&lt;/p&gt;
&lt;p&gt;Due to a lack of time and because I don’t use Burnex anymore in the products I maintain, I deprecated the project in early 2026. Since then, &lt;a href=&quot;https://github.com/achedeuzot&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Klemen Sever&lt;/a&gt; offered to take over the project, and I have transferred ownership.&lt;/p&gt;</content:encoded></item><item><title>Display channel users count with Elixir/Phoenix + React/Redux</title><link>https://benjamin.piouffle.com/blog/display-channel-users-count-elixir-phoenix-react-redux/</link><guid isPermaLink="true">https://benjamin.piouffle.com/blog/display-channel-users-count-elixir-phoenix-react-redux/</guid><description>Implementing an anonymized and fast users count feature that can scale using Phoenix Presence.</description><pubDate>Tue, 21 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A few months ago, we decided to implement a users count feature on
&lt;a href=&quot;https://captainfact.io&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;CaptainFact&lt;/a&gt;’s videos pages. It had to be reliable,
light and simple. We also wanted to differentiate between logged-in and anonymous users.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Banner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1102&quot; height=&quot;388&quot; src=&quot;https://benjamin.piouffle.com/_astro/banner.I6_JC4wh_ZWcbnJ.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The most interesting read I had at the time on this subject was a
&lt;a href=&quot;https://medium.com/@pejrich/tracking-anonymous-unauthorized-users-with-elixir-phoenix-channels-and-presence-cfec1b93c1b0&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;medium article&lt;/a&gt;
which has one major flaw: the &lt;strong&gt;full&lt;/strong&gt; users list is returned from the backend and the count
occurs on the frontend (which actually respects the default behaviour of &lt;code&gt;Phoenix.Presence&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Depending on your business, it can represent a privacy issue (you don’t especially
want anyone to be able to know who’s connected to your channel) as well as a performance
issue.&lt;/p&gt;
&lt;p&gt;In the following article, I’ll show you how I implemented &lt;code&gt;Phoenix.Presence&lt;/code&gt; in such a way that
it only returns the total of connected / anonymous users. We’ll then see how to bind it
to &lt;code&gt;Redux&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;backend&quot;&gt;Backend&lt;/h2&gt;
&lt;h3 id=&quot;implementing-phoenixpresence&quot;&gt;Implementing &lt;code&gt;Phoenix.Presence&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The first thing you want is to implement your own tracker:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lib/my_app_web/presence.ex&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyAppWeb&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Presence&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  @moduledoc &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  Provides presence tracking to channels and processes.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  See the [`Phoenix.Presence`](http://hexdocs.pm/phoenix/Phoenix.Presence.html)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  docs for more details.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  # Replace the values below with your app&apos;s values&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  use&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Phoenix&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Presence&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;otp_app:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; :my_app&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pubsub_server:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyApp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;PubSub&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This implementation is enough if you want to return the classic users list (for
example in a chat). In our case we want to override the default fetch to return
only the users count, and not the full users list:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;@doc &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;Overrides the default fetch. Instead of returning the full users list,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;we only return the count of open sockets.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;This map is what will be returned to the frontend.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; fetch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_topic&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, entries) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  %{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;viewers&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; count_presences&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(entries, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;viewers&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;users&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; count_presences&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(entries, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;users&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; count_presences&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(entries, key) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  case&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get_in&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(entries, [key, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:metas&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    nil&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    metas &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; length&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(metas)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;binding-the-presence-module&quot;&gt;Binding the presence module&lt;/h2&gt;
&lt;h3 id=&quot;add-your-new-module-to-your-apps-supervisor&quot;&gt;Add your new module to your app’s supervisor&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;lib/my_app/application.ex&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defmodule&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyApp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Application&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  use&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Application&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_args&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    import&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Supervisor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Spec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    # Define workers and child supervisors to be supervised&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    children &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;      # Presence to track number of connected users to a channel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;      supervisor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;CaptainFactWeb&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Presence&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, []),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;      ..&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;plugging-presence-on-the-channel&quot;&gt;Plugging Presence on the channel&lt;/h3&gt;
&lt;p&gt;Last thing you need to do is to plug your new &lt;code&gt;Presence&lt;/code&gt; module to your channel.
This part depends of how you’ve implemented channels authentication, in our case
we detect an authenticated channel by setting a &lt;code&gt;user_id&lt;/code&gt; in the channel attributes.&lt;/p&gt;
&lt;p&gt;Add the two following functions to the channel you want to track:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lib/my_app_web/channels/my_channel.ex&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;@doc &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;Register a public connection in presence tracker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handle_info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:after_join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, socket &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;assigns:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;user_id:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Presence&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;track&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(socket, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:viewers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, %{})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  push_presence_state&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(socket)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:noreply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, socket}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;@doc &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;Register a user connection in presence tracker&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handle_info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:after_join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, socket &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;assigns:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; %{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;user_id:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; user_id}}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Presence&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;track&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(socket, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:users&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, %{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;user_id:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; user_id})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  push_presence_state&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(socket)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:noreply&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, socket}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;defp&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; push_presence_state&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(socket) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(socket, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;presence_state&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Presence&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;list&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(socket))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then call these in you &lt;code&gt;join/3&lt;/code&gt; function when it succeeds:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;elixir&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;my_channel&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;_payload&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, socket) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  send&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:after_join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, %{}, socket}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it for the backend !&lt;/p&gt;
&lt;h2 id=&quot;frontend&quot;&gt;Frontend&lt;/h2&gt;
&lt;p&gt;We now need to plug the channel presence messages to update our frontend. This
example uses Redux, but you can easily transpose it for another store system.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;app/state/presence/reducer.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { handleActions, createAction } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;redux-actions&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Record } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;immutable&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; setPresence&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; createAction&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;PRESENCE/SET&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; presenceDiff&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; createAction&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;PRESENCE/DIFF&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; INITIAL_STATE&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  viewers: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({count: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  users: &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Record&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({count: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; PresenceReducer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handleActions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  [setPresence]: (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;merge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(payload),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  [presenceDiff]: (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;state&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: {&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;leaves&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;joins&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;withMutations&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;record&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; record&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;updateIn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;viewers&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;count&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; joins.viewers.count) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; leaves.viewers.count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;updateIn&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;([&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;users&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;count&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; joins.users.count) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; leaves.users.count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;INITIAL_STATE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; PresenceReducer&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the final binding on channel:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;app/state/my_channel/effects.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { Socket } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;phoenix&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { setPresence, presenceDiff } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;../my_channel/reducer&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * Effect to dispatch. Joins a channel &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; joinChannel&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; socket&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Socket&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;SOCKET_URL&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; channel&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; socket.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;channel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;my_channel&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  channel.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;presence_state&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;presenceState&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setPresence&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(presenceState)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  channel.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;presence_diff&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;diff&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; dispatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;presenceDiff&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(diff)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  channel.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;join&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; channel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And voilà! Add a component to render this stuff:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; React &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; PropTypes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;prop-types&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { connect } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react-redux&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; mapStateToProps&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {presence: {nbUsers, nbViewers}} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ({nbUsers, nbViewers})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Presence&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ({&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;nbUsers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;nbViewers&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;presence&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;primary&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;{nbUsers} users&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;viewers&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;{nbViewers} viewers&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Presence.propTypes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  nbUsers: PropTypes.number.isRequired,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  nbViewers: PropTypes.number.isRequired,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; connect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(mapStateToProps)(Presence)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you’ll end up with a nice anonimized and well-optimized counter:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Final Counter&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;273&quot; height=&quot;45&quot; src=&quot;https://benjamin.piouffle.com/_astro/counter.Dgf8LCKR_ENL1h.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;All CaptainFact’s code is open-source (AGPL3). You can find the API code
on &lt;a href=&quot;https://github.com/CaptainFact/captain-fact-api&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;https://github.com/CaptainFact/captain-fact-api&lt;/a&gt; and the frontend code
on &lt;a href=&quot;https://github.com/CaptainFact/captain-fact-frontend&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;https://github.com/CaptainFact/captain-fact-frontend&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Fact-checking et score de crédibilité : entre subjectivité et fausses interprétations, le cas de PolitiFact</title><link>https://benjamin.piouffle.com/blog/fact-checking-et-score-de-credibilite-politifact/</link><guid isPermaLink="true">https://benjamin.piouffle.com/blog/fact-checking-et-score-de-credibilite-politifact/</guid><description>Peut-on calculer, à posteriori du fact-checking, une note qui jugerait de la factualité d&apos;un·e intervenant·e ?</description><pubDate>Tue, 13 Mar 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;This article was first posted on &lt;a href=&quot;https://medium.com/captainfact/fact-checking-et-score-de-credibilite-politifact-9cf9e4b6cab1&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Medium&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;br&gt;
&lt;p&gt;&lt;img alt=&quot;CaptainFact&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;2280&quot; height=&quot;267&quot; src=&quot;https://benjamin.piouffle.com/_astro/banner.BtWdnO3k_CJxQw.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;C’est une demande qui revient régulièrement sur &lt;a href=&quot;https://captainfact.io&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;CaptainFact&lt;/a&gt; : pourrait-on calculer, à posteriori du fact-checking, une note qui jugerait de la factualité des intervenant·e·s ?&lt;/p&gt;
&lt;p&gt;Loin d’être de l’ordre de la science-fiction, cette idée est en fait déjà appliquée outre-atlantique par le site &lt;a href=&quot;http://www.politifact.com/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;politifact.com&lt;/a&gt; qui met en avant ses statistiques de vérification par personnalité. On y découvre que &lt;a href=&quot;http://www.politifact.com/personalities/donald-trump/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Donald Trump&lt;/a&gt; ne dit la vérité que sur 31% des affirmations vérifiées par le service là où son prédécesseur &lt;a href=&quot;http://www.politifact.com/personalities/barack-obama/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Barack Obama&lt;/a&gt; est à 76%.&lt;/p&gt;
&lt;p&gt;Bien qu’elle puisse sembler attirante pour trier l’information plus vite, l’idée d’un score de crédibilité est aussi dangereuse qu’elle est probablement inefficace et ce même (surtout ?) si le travail de vérification est fait de manière collaborative, en encourageant la confrontation des sources comme nous cherchons à le faire sur &lt;em&gt;CaptainFact&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;toutes-les-fausses-informations-ne-se-valent-pas&quot;&gt;Toutes les fausses informations ne se valent pas&lt;/h2&gt;
&lt;p&gt;Faire une erreur en annonçant des chiffres surréalistes sur les importations de produits laitiers n’a pas le même impact que de nier l’existence des chambres à gaz. Chez PolitiFact on ne s’encombre pas de cet aspect : une affirmation est vraie, plutôt vraie, à moitié vraie, plutôt fausse, fausse, ou un gros bobard. La nature de ce bobard importe peu : &lt;a href=&quot;http://www.politifact.com/california/statements/2016/nov/28/donald-trump/pants-fire-trumps-claim-about-california-voter-fra/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;inventer une fraude électorale&lt;/a&gt;, &lt;a href=&quot;http://www.politifact.com/truth-o-meter/statements/2016/sep/01/donald-trump/donald-trump-repeats-pants-fire-claim-about-30-mil/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;multiplier par trois le nombre d’immigrés&lt;/a&gt; ou &lt;a href=&quot;http://www.politifact.com/truth-o-meter/statements/2008/dec/03/barack-obama/no-mccains-ads-havent-all-been-negative/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;prétendre à tort que les pubs de McCain lors des élections étaient plutôt négatives&lt;/a&gt; vous vaudront tous les trois un &lt;em&gt;“Pants on fire”&lt;/em&gt; - le bonnet d’âne de la fake news chez PolitiFact.&lt;/p&gt;
&lt;h2 id=&quot;sélectionner-les-informations-quon-vérifie-cest-attribuer-un-score-subjectif&quot;&gt;Sélectionner les informations qu’on vérifie, c’est attribuer un score subjectif&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.politifact.com/truth-o-meter/article/2018/feb/12/principles-truth-o-meter-politifacts-methodology-i/#How%20we%20choose%20claims&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Pour être sélectionnée&lt;/a&gt;, une affirmation doit d’abord attirer l’attention d’un·e journaliste, d’un lecteur ou d’une lectrice (un tiers de leurs publications sont issues de suggestions). Elle doit ensuite répondre à un ou plusieurs des critères suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Être vérifiable&lt;/li&gt;
&lt;li&gt;Être trompeuse ou sonner fausse&lt;/li&gt;
&lt;li&gt;Être significative (les erreurs mineures ou une langue qui fourche de manière évidente sont ignorées)&lt;/li&gt;
&lt;li&gt;Être sujette à partage ou à répétition par le public&lt;/li&gt;
&lt;li&gt;Une personne typique peut être amenée à se questionner sur sa véracité&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Même en admettant une totale impartialité des journalistes, la mise de côté de leurs biais idéologiques et la parité de leurs propres lectures, on peut raisonnablement penser que ces règles poussent à privilégier la vérification des affirmations qu’on pense être fausses.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;PolitiFact Truth-O-Meter scorecard&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;760&quot; height=&quot;325&quot; src=&quot;https://benjamin.piouffle.com/_astro/politifact-scorecard.eZpPaYFv_m9kX0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Aucun effort ne semble en tous cas être fait pour apporter une vérification systématique et quand bien même la volonté serait là, vérifier toutes les affirmations d’un·e intervenant·e n’est ni faisable ni souhaitable.&lt;/p&gt;
&lt;p&gt;Mais que peut bien vouloir dire ce score s’il ne prend pas en compte 100% des affirmations vérifiables ?&lt;/p&gt;
&lt;h2 id=&quot;linterprétation&quot;&gt;L’interprétation&lt;/h2&gt;
&lt;p&gt;Malgré le fait que la représentativité de ces vérifications ne soit nulle part garantie, PolitiFact ne se gêne pas pour présenter ses scores comme un &lt;strong&gt;“Truth-O-Meter”&lt;/strong&gt;. Autrement dit, un appareil de mesure de vérité. Une mesure si scientifique et objective qu’elle leur permet même de &lt;a href=&quot;http://www.politifact.com/truth-o-meter/lists/people/comparing-hillary-clinton-donald-trump-truth-o-met/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;comparer les candidats entre eux&lt;/a&gt; !&lt;/p&gt;
&lt;p&gt;Et tant pis si quand &lt;strong&gt;PolitiFact&lt;/strong&gt; annonçait en 2016 30.5% d’affirmations fausses chez les &lt;strong&gt;démocrates&lt;/strong&gt; (à l’exception d’Obama) là où son équivalent du &lt;a href=&quot;https://www.washingtonpost.com/news/fact-checker/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Washington Post Fact Checker&lt;/a&gt; arrivait lui à un chiffre de 57.1% - soit presque deux fois plus (source: &lt;a href=&quot;https://www.americanpressinstitute.org/wp-content/uploads/2016/10/2016-apsa-politifact.pdf&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;American Press Institute&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C’est pourtant ici que réside la question la plus importante : Comment le public va-t-il interpréter cette note ? Quelle information va-t-il en retirer ?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/search?q=politifact%20scorecard&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Une petite recherche sur Twitter&lt;/a&gt; permet de constater que beaucoup d’utilisateurs perçoivent effectivement ce score comme &lt;strong&gt;une mesure absolue&lt;/strong&gt; qui leur permet de comparer de manière crédible qui ment le plus entre Trump et Obama, entre démocrates et républicains :&lt;/p&gt;
&lt;p&gt;Un exemple typique : trois affirmations classées comme fausses sur PolitiFact suffisent pour être fiché comme un menteur compulsif, et le simple fait de citer l’individu invalide l’ensemble du propos.&lt;/p&gt;
&lt;p&gt;Le travail de fact-checking n’est ici plus utilisé pour construire une argumentation factuelle mais pour servir un message idéologique dont le score constitue l’argument d’autorité. Score dont la légitimité reste à prouver.&lt;/p&gt;
&lt;h2 id=&quot;dear-politifact-please-focus-on-your-job-&quot;&gt;Dear PolitiFact, please focus on your job 💛&lt;/h2&gt;
&lt;p&gt;Le travail de fact-checking de PolitiFact est précieux. Sa valeur ajoutée réside dans la vérification de points précis et potentiellement délicats par des équipes dont l’efficacité a plusieurs fois été saluée.&lt;/p&gt;
&lt;p&gt;Offrir aux lecteurs un résumé grossier, une caricature, par un pourcentage dont &lt;strong&gt;la fiabilité statistique ne saurait être démontrée&lt;/strong&gt; semble aller à l’encontre de cette mission.&lt;/p&gt;
&lt;p&gt;Coller des étiquettes sur des médias et des individus en se basant sur des données discutables ne semble définitivement pas être une bonne chose à faire si l’on espère agir avec la confiance du public.&lt;/p&gt;</content:encoded></item><item><title>The urge for a collaborative, citizen fact-checking platform</title><link>https://benjamin.piouffle.com/blog/the-urge-for-a-collaborative-citizen-fact-checking-platform/</link><guid isPermaLink="true">https://benjamin.piouffle.com/blog/the-urge-for-a-collaborative-citizen-fact-checking-platform/</guid><description>Access to information is no longer a problem. We now need ways to better sort this information.</description><pubDate>Thu, 19 Oct 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;This article was first posted on &lt;a href=&quot;https://medium.com/captainfact/the-urge-for-a-collaborative-citizen-fact-checking-platform-a0ce035bc608&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Medium&lt;/a&gt;&lt;/strong&gt;.
Text has been left untouched but graphical resources have been updated.&lt;/p&gt;
&lt;hr&gt;
&lt;br&gt;
&lt;p&gt;The Internet has drawn us into strange places lately. It has helped us to share information faster and at a larger scale, but it has also shown many weaknesses when it comes to verifying that information.&lt;/p&gt;
&lt;p&gt;The biggest concern that has emerged from this is probably the disregard for facts: on the Internet, no matter what your beliefs are, you’ll find sources to confirm them. Our &lt;a href=&quot;https://en.wikipedia.org/wiki/Confirmation_bias&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;confirmation bias&lt;/a&gt;, with the help of Google’s and Facebook’s algorithms, has locked us into &lt;a href=&quot;https://en.wikipedia.org/wiki/Filter_bubble&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;filter bubbles&lt;/a&gt; - we follow people and medias that don’t contradict too much with our view of the world and we’re often shocked when we finally debate with someone who thinks differently.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Who wants to hear the truth, when they can hear that they&apos;re right. Our desire for affirmation is stronger than our desire for truth.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;642&quot; height=&quot;326&quot; src=&quot;https://benjamin.piouffle.com/_astro/tweet-cjoh.D0eWe9JY_Z1wenzP.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;centralized-fact-checkers&quot;&gt;Centralized fact-checkers&lt;/h2&gt;
&lt;p&gt;Serious medias are probably the most concerned about this misinformation issue. They see a &lt;a href=&quot;http://fortune.com/2017/05/24/trust-media/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;historic wave of distrust&lt;/a&gt; and often have trouble attracting readers: it’s easier to get people to click on your article when you’re selling them the “&lt;em&gt;ten reasons that prove aliens are among us&lt;/em&gt;” than a deep and complicated analysis of a political subject.&lt;/p&gt;
&lt;p&gt;One of the few responses we’ve seen so far from traditional medias is for them to try to act as a single source of truth. In France, the newspaper &lt;em&gt;Le Monde&lt;/em&gt; has created a tool called &lt;em&gt;&lt;a href=&quot;http://www.lemonde.fr/verification/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Le Décodex&lt;/a&gt;&lt;/em&gt; to which you give a website and that tells you if you should trust it or not. But can we rely on a single, centralized media to tell us what we should read and what we should not ?&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Décodex - “Enter a web page URL or a site name to know if the source is reliable or not”&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;800&quot; height=&quot;264&quot; src=&quot;https://benjamin.piouffle.com/_astro/decodex.Dl6WzJnK_tSfUx.webp&quot; srcset=&quot;&quot;&gt;&lt;em&gt;Décodex - “Enter a web page URL or a site name to know if the source is reliable or not”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And what will happen when less professional medias bring their own &lt;em&gt;Décodex&lt;/em&gt;, when a conservative news media creates an extension warning its users that they should not read this liberally-biased media, and when liberal entities come with something to block every conservative posts from their news feed ?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Truth, especially in politics, cannot rely only on a central authority.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Another big issue with this approach is &lt;strong&gt;granularity&lt;/strong&gt;. A reference media can make mistakes, and the worst fake news website can sometimes tell the truth. By telling people who they should trust or not, we’re only reinforcing the cleavage and comforting an increasing number of skeptics in their belief that traditional medias “do not want them to know the truth”.&lt;/p&gt;
&lt;p&gt;If we want to give them some perspective, we definitely need to add some precision to this picture: verification must be &lt;strong&gt;per statement&lt;/strong&gt; - not per media!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We’ve also seen some interesting responses&lt;/strong&gt;: along with the &lt;em&gt;Décodex&lt;/em&gt;, &lt;em&gt;LeMonde&lt;/em&gt; also created an ambitious fact-checking platform: &lt;a href=&quot;http://www.lemonde.fr/les-decodeurs/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Les Décodeurs&lt;/a&gt;, where journalists verify specific points from articles, debates and speeches.
This initiative has many brothers and sisters: &lt;a href=&quot;http://www.liberation.fr/desintox,99721&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;LibéDésintox&lt;/a&gt; for Libération (FR), &lt;a href=&quot;http://www.politifact.com&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Politifact&lt;/a&gt; (US), &lt;a href=&quot;http://www.factcheck.org/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;FactCheck.org&lt;/a&gt;…&lt;/p&gt;
&lt;p&gt;The work done by all these services is extremely valuable: they focus on specific arguments and give sources and explanations that are usually hard to argue with. But here is the big problem : &lt;strong&gt;Centralized fact-checkers will never be able to deal with the enormous amount of data produced on the Internet today&lt;/strong&gt;. From PolitiFact’s &lt;a href=&quot;http://www.politifact.com/truth-o-meter/article/2017/dec/15/we-started-fact-checking-partnership-facebook-year/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;own words&lt;/a&gt; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s do an exercise: For most of 2017, there were five fact-checking organizations participating in this project in the United States. (It’s also running in France and Germany.) Let’s say they all fact-checked as many URLs as we did - 1,722, that’s 8,610 articles fact-checked a year.
Now let’s say the universe of false news stories of 1,000 a week - that’s 52,000 articles a year.
In that scenario, the best we’re doing is covering 16.5 percent of the field. In all likelihood, the percentage is lower.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And we’re just talking about fake news here, not misinformation in general !&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If we owe to address the issue of online misinformation, we have to let the citizen enter the arena of fact-checking.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;is-wikipedias-model-applicable-to-fact-checking&quot;&gt;Is Wikipedia’s model applicable to fact checking?&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Wikipedia - The Free Encyclopedia&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;400&quot; height=&quot;400&quot; src=&quot;https://benjamin.piouffle.com/_astro/wikipedia.DzZyAS6L_Z1HovKi.webp&quot; srcset=&quot;&quot;&gt;&lt;em&gt;Wikipedia - The Free Encyclopedia&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Wikipedia’s biggest strength is having been able to build a collaborative platform on which &lt;strong&gt;the multiplicity and the diversity&lt;/strong&gt; of the contributions create a certain form of neutrality. And &lt;a href=&quot;https://en.wikipedia.org/wiki/Reliability_of_Wikipedia&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;most studies on the question&lt;/a&gt; agree on the fact that for the most important subjects, Wikipedia has at least the same level of reliability than others encyclopedias; especially because it systematically &lt;strong&gt;asks for sources&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;could-we-apply-the-same-model-for-our-day-to-day-information-&quot;&gt;&lt;strong&gt;Could we apply the same model for our day-to-day information ?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Well, Wikipedia is great for non-cleaving subjects. But &lt;a href=&quot;https://en.wikipedia.org/wiki/Astroturfing&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;astroturfing&lt;/a&gt; proves that when it comes to sensitive and political subjects, a system that allows anyone to edit anything with very few consequences has some drawbacks; &lt;strong&gt;having a sane debate requires rules&lt;/strong&gt;. And rules can actually be fun; could we play games without cheating otherwise?&lt;/p&gt;
&lt;p&gt;A brilliant model to support this idea is &lt;a href=&quot;https://stackoverflow.blog/2009/05/18/a-theory-of-moderation/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Stack Overflow&lt;/a&gt;. By using reputation, votes, achievements and (reputation) bounties they have created a platform which makes people willing to contribute to what may seems like a tedious task (fixing other people’s code problems) and that naturally filters pollutive content.&lt;/p&gt;
&lt;h2 id=&quot;collaborative-real-time-fact-checking---using-games-to-fight-misinformation&quot;&gt;Collaborative, real-time fact checking - using games to fight misinformation&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&quot;Banner&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1200&quot; height=&quot;628&quot; src=&quot;https://benjamin.piouffle.com/_astro/banner-cover.f_9CJFRH_fbjOX.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;For the last year we’ve been thinking and experimenting with this idea through a project named &lt;strong&gt;&lt;a href=&quot;https://captainfact.io&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;CaptainFact.io&lt;/a&gt;&lt;/strong&gt;, a set of tools that could help us to collectively verify information &lt;strong&gt;anywhere&lt;/strong&gt; on the Internet.&lt;/p&gt;
&lt;p&gt;The goal: approaching Wikipedia’s reliability by using &lt;strong&gt;sources, warnings and collective moderation&lt;/strong&gt;, with the &lt;strong&gt;gamification&lt;/strong&gt; approach that made &lt;a href=&quot;https://blog.codinghorror.com/the-gamification/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Stack Overflow&lt;/a&gt; a fun and safe place to be -applied to our daily news.&lt;/p&gt;
&lt;p&gt;This is currently pursued by the development of 3 linked tools:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;A video overlay&lt;/strong&gt; (thanks to a web browser extension) that add sources and context to the videos you’re watching on the Internet. Each statement can be verified and we show with a small icon if it is believed to be true or false, based on users votes.&lt;/li&gt;
&lt;/ol&gt;
&lt;center&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/4-_nnwgqw9c&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;**A debate platform **that aggregates this information in a place where you can have rich and focused discussions by working &lt;strong&gt;point by point, argument by argument&lt;/strong&gt; - instead of taking the content as a whole like almost all today’s comment systems do.&lt;/li&gt;
&lt;/ol&gt;
&lt;center&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/IJrmHU13lWY&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/center&gt;
&lt;h2 id=&quot;ethics-21st-centurys-organizations-and-big-brother&quot;&gt;&lt;strong&gt;Ethics, 21st century’s organizations and big brother&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;If you’re concerned about privacy, you’re probably thinking right now that an extension that checks every website and video you’re watching is extremely dangerous, and you’re right. Though we respect your privacy and won’t log or sell any of this data, you shouldn’t trust us or anyone on this point.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/2000/1*gu8VzMOcXK1rsTek7iMRkg.jpeg&quot; alt=&quot;Ability to disable CaptainFact in one click&quot;&gt;&lt;em&gt;Ability to disable CaptainFact in one click&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What can you trust ? &lt;strong&gt;Open-source&lt;/strong&gt; code and &lt;strong&gt;open organizations&lt;/strong&gt;. As it is for Mozilla Firefox, we should be able to demonstrate with proof that we don’t (and won’t) track your online activity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://captainfact.io&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;CaptainFact&lt;/a&gt; is a non-profit project&lt;/strong&gt; that you can back on &lt;a href=&quot;https://opencollective.com/captainfact_io&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;OpenCollective&lt;/a&gt; - transparent funds, transparent code, and collective decisions on how to build it.&lt;/p&gt;
&lt;h2 id=&quot;what-now-and-how-can-i-participate-&quot;&gt;What now, and how can I participate ?&lt;/h2&gt;
&lt;p&gt;The first iteration is ready: we have a debate platform and an extension that will bring these debated information down to the videos we’re watching online. I believe they are now ready to be tested on the battleground with a small number of actors to adjust the variables and see what can be improved.&lt;/p&gt;
&lt;p&gt;Various roles and skills will be required to put this project on track:&lt;/p&gt;
&lt;h3 id=&quot;content-creators&quot;&gt;Content creators&lt;/h3&gt;
&lt;p&gt;If you are a Youtube creator, CaptainFact can help you to better engage your community, to bring trust on your content and to make it even richer.
By using CaptainFact, your content is peer-reviewed by your entire community.&lt;/p&gt;
&lt;p&gt;Beside exceptions like &lt;a href=&quot;https://www.wikitribune.com/&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;WikiTribune&lt;/a&gt; very few medias can say the same.&lt;/p&gt;
&lt;h3 id=&quot;beta-testers&quot;&gt;Beta testers&lt;/h3&gt;
&lt;p&gt;For now, CaptainFact is in private beta (invitation only). Though it is ready to scale up fast, bringing it to a very large number of people right now would be risky. We need to test and improve the existing rules, like how many negative votes a new user can make each day. Finding good values for these &lt;strong&gt;can only be done through experience&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We’re particularly interested in having &lt;strong&gt;journalists&lt;/strong&gt; joining us, your experience with news and information verification would be very helpful to see how such tools could compare to the job that you do by yourself.&lt;/p&gt;
&lt;h3 id=&quot;developers&quot;&gt;Developers&lt;/h3&gt;
&lt;p&gt;There are many ways to improve and optimize the existing code, and many other ways for the data to be re-used. Strongly motivated developers are welcome to contribute and take a central part in this new and fast-growing project!
For those interested, current stack uses Elixir + Phoenix (server) and React (frontend + browser extension).&lt;/p&gt;
&lt;h3 id=&quot;graphic-designers&quot;&gt;Graphic designers&lt;/h3&gt;
&lt;p&gt;If you’re a graphic designer, there is cool stuff to work on for CaptainFact. We especially need fun graphics for &lt;a href=&quot;https://captainfact.io/help/achievements&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;achievements&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;lawyers&quot;&gt;Lawyers&lt;/h3&gt;
&lt;p&gt;We’re in favor of a &lt;a href=&quot;https://captainfact.io/help/censorship_requests&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;strong free-speech policy&lt;/a&gt;. Law geek’s passionate about these questions could help us achieving our goals without conflicting with international laws.&lt;/p&gt;
&lt;h3 id=&quot;translators&quot;&gt;Translators&lt;/h3&gt;
&lt;p&gt;At the moment the website is available in English and French. We’d love to have it available in Spanish, German and any other language that could help to bring these tools to a wider community.&lt;/p&gt;
&lt;h3 id=&quot;enthusiasts&quot;&gt;Enthusiasts&lt;/h3&gt;
&lt;p&gt;This is a collaborative project and we need people to spread the word. Community managers, students interested in media literacy… &lt;a href=&quot;mailto:contact@captainfact.io&quot;&gt;contact us&lt;/a&gt; if you’re motivated about working together!&lt;/p&gt;
&lt;h3 id=&quot;share-the-love-️&quot;&gt;Share the love ❤️&lt;/h3&gt;
&lt;p&gt;You can follow the project on &lt;a href=&quot;https://twitter.com/CaptainFact_io&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Twitter&lt;/a&gt; and on &lt;a href=&quot;https://www.facebook.com/CaptainFact.io&quot; class=&quot;external-link&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Facebook&lt;/a&gt;&lt;/p&gt;</content:encoded></item></channel></rss>