<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Push notifications on back(d)</title><link>https://fernandezvara.github.io/backd/docs/build/push/</link><description>Recent content in Push notifications on back(d)</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://fernandezvara.github.io/backd/docs/build/push/index.xml" rel="self" type="application/rss+xml"/><item><title>Devices</title><link>https://fernandezvara.github.io/backd/docs/build/push/devices/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/build/push/devices/</guid><description>&lt;p&gt;A &lt;strong&gt;device&lt;/strong&gt; is one app installation (or one browser) that can receive pushes for a user. Apps register it with &lt;code&gt;POST /_auth/devices&lt;/code&gt;; backd owns the registry, so it can move tokens between users, drop them when a session ends and clean up after erasure, which an app&amp;rsquo;s own collection can&amp;rsquo;t.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X POST &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$BACKD&lt;/span&gt;&lt;span class="s2"&gt;/v1/acme/_auth/devices&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$SESSION&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; -H &lt;span class="s1"&gt;&amp;#39;Content-Type: application/json&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{&amp;#34;platform&amp;#34;: &amp;#34;android&amp;#34;, &amp;#34;token&amp;#34;: &amp;#34;&amp;lt;FCM registration token&amp;gt;&amp;#34;, &amp;#34;name&amp;#34;: &amp;#34;Ana&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s Pixel&amp;#34;}&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;d3c9ljp8hc2g00b6s1m0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;android&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Ana&amp;#39;s Pixel&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;created_at&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;…&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;last_seen&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;…&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="the-endpoints"&gt;The endpoints&lt;a class="hd-anchor" href="#the-endpoints" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;All of these need a &lt;strong&gt;user session&lt;/strong&gt;: an API key (or &lt;code&gt;X-Backd-On-Behalf-Of&lt;/code&gt;) can&amp;rsquo;t register devices.&lt;/p&gt;</description></item><item><title>Sending pushes</title><link>https://fernandezvara.github.io/backd/docs/build/push/sending/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/build/push/sending/</guid><description>&lt;p&gt;A function that declares &lt;a href="../../functions/reference/"&gt;&lt;code&gt;push&lt;/code&gt;&lt;/a&gt; in its &lt;code&gt;function.yaml&lt;/code&gt; has &lt;code&gt;ctx.push.send&lt;/code&gt;. The call answers at once; backd&amp;rsquo;s workers deliver.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;user&lt;/span&gt;: &lt;span class="kt"&gt;order.owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// or users: [...], or audience (below)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;order-shipped&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// a template of the realm, or title + body (raw)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;order_no&lt;/span&gt;: &lt;span class="kt"&gt;order.no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;eta&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;tomorrow&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;group&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sb"&gt;`order-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;high&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// r = { send_id: &amp;#34;ps_…&amp;#34;, users: 1, jobs: 1, queued: 1, limited: 0, no_devices: 0 }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# function.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;push: true # or push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;kinds: [order-shipped], audience&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;}&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="who"&gt;Who&lt;a class="hd-anchor" href="#who" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Give exactly one of:&lt;/p&gt;</description></item><item><title>Records, test send and metrics</title><link>https://fernandezvara.github.io/backd/docs/build/push/records/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/build/push/records/</guid><description>&lt;h2 id="the-record-of-a-send"&gt;The record of a send&lt;a class="hd-anchor" href="#the-record-of-a-send" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Every send leaves one record, kept for &lt;code&gt;push.send_retention&lt;/code&gt; (30 days by default). It holds &lt;strong&gt;counts, never content&lt;/strong&gt;: no title, body, data or token, and no user ids (those live only in the send&amp;rsquo;s jobs, which follow the realm&amp;rsquo;s &lt;a href="../../functions/jobs/"&gt;job retention&lt;/a&gt;).&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Field&lt;/th&gt;
 &lt;th&gt;Meaning&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;kind&lt;/code&gt;, &lt;code&gt;sender&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;The send, its template kind (&lt;code&gt;raw&lt;/code&gt; for a message the function wrote), who sent it (&lt;code&gt;function:&amp;lt;database&amp;gt;/&amp;lt;name&amp;gt;&lt;/code&gt; or &lt;code&gt;admin:&amp;lt;actor&amp;gt;&lt;/code&gt;) and when&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;users&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;How many users were named; &lt;code&gt;null&lt;/code&gt; for an audience&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;queued&lt;/code&gt;, &lt;code&gt;limited&lt;/code&gt;, &lt;code&gt;no_devices&lt;/code&gt;, &lt;code&gt;no_consent&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Users handed to delivery, users over their limit, users with no device to reach (a silent push skips browsers), users who don&amp;rsquo;t hold the &lt;a href="../../auth/consents/"&gt;consent&lt;/a&gt; the send requires&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;sent&lt;/code&gt;, &lt;code&gt;invalid&lt;/code&gt;, &lt;code&gt;failed&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Devices the provider accepted, devices removed as dead, devices not delivered to&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;planned&lt;/code&gt;, &lt;code&gt;batches&lt;/code&gt;, &lt;code&gt;batches_done&lt;/code&gt;, &lt;code&gt;units&lt;/code&gt;, &lt;code&gt;units_done&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;How far the work is&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;completed&lt;/code&gt;, &lt;code&gt;completed_at&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Everything is done&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backd push sends --realm acme &lt;span class="c1"&gt;# the latest, newest first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backd push sends --realm acme --kind order-shipped
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backd push sends --realm acme --function main/notify --limit &lt;span class="m"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;backd push sends --realm acme --id ps_d3c9ljp8hc2g00b6s1m0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The admin interface shows the same on its &lt;strong&gt;Push&lt;/strong&gt; page (&lt;a href="../../../operate/administration/admin-ui/#push-notifications"&gt;Admin interface&lt;/a&gt;). The admin API: &lt;code&gt;GET /_admin/push&lt;/code&gt; (the configuration state and the secrets still missing), &lt;code&gt;GET /_admin/push/sends&lt;/code&gt; (filters &lt;code&gt;kind&lt;/code&gt;, &lt;code&gt;function&lt;/code&gt;, &lt;code&gt;since&lt;/code&gt;, &lt;code&gt;until&lt;/code&gt;, &lt;code&gt;limit&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;) and &lt;code&gt;GET /_admin/push/sends/{id}&lt;/code&gt;. Both need the &lt;code&gt;functions&lt;/code&gt; area, and read-only administrators may use them.&lt;/p&gt;</description></item><item><title>From apps</title><link>https://fernandezvara.github.io/backd/docs/build/push/client/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://fernandezvara.github.io/backd/docs/build/push/client/</guid><description>&lt;p&gt;The &lt;a href="../../clients/js/"&gt;JavaScript client&lt;/a&gt; has &lt;code&gt;client.push&lt;/code&gt;, a small layer over the &lt;a href="../devices/"&gt;device endpoints&lt;/a&gt;. It needs a &lt;strong&gt;user session&lt;/strong&gt;: an API key can&amp;rsquo;t register devices.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;backd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;android&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fcmToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Ana&amp;#39;s Pixel&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;backd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// [{ id, platform, name, created_at, last_seen }] (never a token)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;backd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unregister&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// the device this client registered; or unregister(id)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Call&lt;/th&gt;
 &lt;th&gt;What it does&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;register({ platform, token, name? })&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;POST /_auth/devices&lt;/code&gt;. Registers or refreshes; keeps the returned id (&lt;code&gt;client.push.deviceId&lt;/code&gt;) for &lt;code&gt;unregister()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;devices()&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;GET /_auth/devices&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;unregister(id?)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;DELETE /_auth/devices/{id}&lt;/code&gt;; without an id, the device this client registered (&lt;code&gt;false&lt;/code&gt; when there is none)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;registerOnLaunch(getToken, { onError })&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Registers &lt;strong&gt;now&lt;/strong&gt; if signed in and again &lt;strong&gt;after every sign-in&lt;/strong&gt;. &lt;code&gt;getToken&lt;/code&gt; returns what to register, or &lt;code&gt;null&lt;/code&gt; while the app has no token. Returns a function that stops it&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;subscribeWeb({ registration, name?, requestPermission? })&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Subscribes a browser and registers the subscription (below)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="keeping-a-device-registered"&gt;Keeping a device registered&lt;a class="hd-anchor" href="#keeping-a-device-registered" aria-hidden="true"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;A device is removed when its session ends, when it is unseen for &lt;code&gt;push.devices.stale_after&lt;/code&gt;, and when its realm&amp;rsquo;s web key is rotated. So an app registers &lt;strong&gt;at every launch and after every sign-in&lt;/strong&gt;, which is what &lt;code&gt;registerOnLaunch&lt;/code&gt; does:&lt;/p&gt;</description></item></channel></rss>