-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathllms-full.txt
More file actions
13796 lines (8250 loc) · 606 KB
/
llms-full.txt
File metadata and controls
13796 lines (8250 loc) · 606 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Juno
Juno is your self-contained serverless platform for building full-stack web apps without DevOps or backend boilerplate. Developers use their favorite frontend frameworks like React, SvelteKit, or Next.js, and write backend logic in Rust or TypeScript as serverless functions. Everything is bundled into a single WebAssembly (WASM) artifact that runs in a decentralized, stateful environment — under full user ownership — on the Internet Computer. Juno cannot access or modify your code, data, or infrastructure. It supports GitHub Actions for deploys and upgrades, and provides both a CLI and web Console UI for managing projects. The local development environment closely mirrors production, ensuring smooth transitions from build to deployment — all with the privacy and control developers expect from self-hosting.
# Getting Started with Juno
Unless you're looking to solely host your static website, the recommended way to start with Juno is by developing locally using the emulator — a production-like environment with full support for data, authentication, storage, and serverless functions.
It gives you everything you need to build and test your app before deploying anything live.
Here are a few solid places to go from here:
* 🚀 [Start a new project](/docs/start-a-new-project.md) – Scaffold a brand new project with your favorite frontend framework.
* 🔌 [Set up the SDK](/docs/setup-the-sdk.md) – Integrate Juno into an existing app.
* 🧪 [Run your project locally](/docs/guides/local-development.md) – Use the emulator to build and test locally in an environment that mirrors production.
* 🛰️ [Deploy with a Satellite](/docs/create-a-satellite.md) – When you're ready to go live, deploy your project to its own container.
---
## How It Works
Juno is your own self-contained execution space.
No DevOps. No backend boilerplate. No surprise complexity.
You build your frontend using the frameworks you love — React, SvelteKit, Next.js, you name it.
Need backend logic? Just drop in a serverless function written in Rust or TypeScript.
Everything gets bundled into a single deployable WebAssembly (WASM) container. One artifact. One push. That's your app.
It runs in an unstoppable environment that holds its entire state — data, logic, and storage.
No cold starts. Your functions execute instantly.
And here's the beauty of it: Juno controls nothing.
It has zero access to your code, data, or infrastructure. Everything runs under your ownership. Think of it as the space between self-hosting and the serverless cloud — a reimagined model for application development.
You manage your projects and supporting modules — themed around space mythology — using either a CLI or the Console UI, depending on your workflow.
To strengthen this principle of non-interference, deploys and upgrades can be handled via GitHub Actions if you choose to opt in — which themselves can't start or stop your app once it's live.
And during development, the environment mirrors production as closely as possible — so you're never caught by “but it worked locally.”
---
## Comparisons
Wondering how Juno stacks up in the real world? Compare it to today's most popular platforms:
* [vs Vercel](/docs/comparison/vs-vercel.md)
* [vs Netlify](/docs/comparison/vs-netlify.md)
* [vs Railway](/docs/comparison/vs-railway.md)
* [vs Heroku](/docs/comparison/vs-heroku.md)
* [vs Self-Hosting](/docs/comparison/vs-self-hosting.md)
---
## Further Details
Learn more about the available products, from auth and data to hosting and functions.
* [Authentication](/docs/build/authentication.md)
* [Datastore](/docs/build/datastore.md)
* [Storage](/docs/build/storage.md)
* [Hosting](/docs/build/hosting.md)
* [Functions](/docs/build/functions.md)
* [Analytics](/docs/build/analytics.md)
* [Monitoring](/docs/management/monitoring.md)
* [Snapshots](/docs/management/snapshots.md)
# Start a New Project
With Juno, a project typically lives in a single repository — combining your frontend, serverless functions, and configuration. Whether you're starting from scratch or extending an existing app, the result is a full-stack project that deploys as a single container.
---
## 🧭 Choose Your Starting Point
There are multiple ways to start a Juno project. Pick what fits best:
* ([Use a Juno Template](#-scaffold-with-a-juno-template)) if you want everything preconfigured
* ([Bring Your Own Framework](#-start-with-your-favorite-framework)) if you’ve already picked a stack
* ([Add Juno to an Existing Project](#-add-juno-to-an-existing-project)) for incremental adoption
---
## 🚀 Scaffold with a Juno Template
One way to get started is by scaffolding a full-stack project using our prebuilt templates — it sets up your frontend framework of choice along with serverless functions and emulator support.
To create a new project, just run:
* npm
* yarn
* pnpm
```
npm create juno@latest
```
```
yarn create juno
```
```
pnpm create juno
```
**Note:**
Supports Astro, Next.js, React, SvelteKit, Vue, and Angular.
---
## ✨ Start with Your Favorite Framework
Prefer to begin with `npx create-next-app`, `npm create svelte@latest`, or any other starter you know well? Totally fine. Set up your frontend however you like, then bring in Juno afterward.
**SSR not supported:**
Juno doesn’t yet support Server Side Rendering (SSR). Your frontend code should run on the client side. We recommend using Static Site Generation (SSG) or prerendering instead.
Once your app is ready, head over to the [SDK Setup Guide](/docs/setup-the-sdk.md) to:
* Install the SDK
* Enable emulator support
* Add serverless functions
* Configure deployment
This gives you full flexibility while keeping everything in one repo.
---
## 🧩 Add Juno to an Existing Project
Already have a project in development or production? You can integrate Juno incrementally.
Start with the [SDK Setup Guide](/docs/setup-the-sdk.md) and bring in only what you need — whether that's authentication, datastore, serverless functions, or all of the above.
---
## One Repo, One App
No matter how you start, Juno follows a simple principle: **one project = one repo = one container**.
Everything — frontend, backend, and app state — is bundled into a single WebAssembly (WASM) container and deployed together.
This architecture keeps development and deployment straightforward, reliable, and fully yours.
# Setup the SDK
To connect your app to a Satellite and use Juno's features — like authentication, data, storage, and serverless functions — you'll need to initialize the SDK.
This guide walks you through how to do that, whether you're using a plugin (Next.js, Vite) or setting things up manually.
**Info:**
If you intend to use Juno solely for **[hosting](/docs/build/hosting.md)** purposes, you may skip the following steps.
---
## TL;DR
1. Call `initSatellite()` in your app code
2. Create a `juno.config` file at the root to define your Satellite
3. Connect code and config — preferably using the `@junobuild/nextjs-plugin` or `@junobuild/vite-plugin`
---
## Initialization
1. Install the Juno SDK:
* npm
* yarn
* pnpm
```
npm i @junobuild/core
```
```
yarn add @junobuild/core @icp-sdk/core @icp-sdk/auth @dfinity/utils
```
```
pnpm add @junobuild/core @icp-sdk/core @icp-sdk/auth @dfinity/utils
```
2. Initialize your Satellite in your web app:
```
import { initSatellite } from "@junobuild/core";await initSatellite();
```
It is generally recommended to initialize globally the library at the top of your application.
---
## Configuration
Juno uses a configuration file to determine which Satellite to connect to.
You can scaffold a minimal `juno.config` file using:
```
npx @junobuild/cli init --minimal
```
This creates a `juno.config` file — in TypeScript, JavaScript, or JSON depending on your preferences — at the root of your project. It contains metadata such as the Satellite ID used during SDK initialization.
---
## Connecting Code and Config
If you're using **Next.js** or **Vite**, we recommend installing the official plugin. It automatically loads values from your config file and injects them into your build as environment variables.
This means you can call `initSatellite()` without passing any parameters, the SDK will read them automatically from `process.env` or `import.meta.env`.
* [Next.js Plugin](/docs/reference/plugins.md#nextjs-plugin)
next.config.js
```
import { withJuno } from "@junobuild/nextjs-plugin";// withJuno wraps your Next.js config and injects values from juno.configexport default withJuno();
```
* [Vite Plugin](/docs/reference/plugins.md#vite-plugin)
vite.config.js
```
import juno from "@junobuild/vite-plugin";// Automatically injects values from juno.config for the buildexport default defineConfig({ plugins: [juno()]});
```
**Note:**
The templates already include both the config file and the plugin setup.
#### Not using a plugin?
You can also pass the Satellite ID manually to the SDK, though using the plugins is the preferred approach:
```
import { initSatellite } from "@junobuild/core";await initSatellite({ satelliteId: "your-actual-satellite-id"});
```
# Local Development
Juno offers something most platforms don't: a full local development environment that closely mirrors production.
## TL;DR
| What | How |
| --- | --- |
| Runtime supported | Docker or Podman |
| Start emulator | `juno emulator start` |
| Stop emulator | `juno emulator stop` |
| Console UI URL | [http://localhost:5866](http://localhost:5866) |
---
## What the Emulator Includes
When you develop locally, you're running an emulator that includes the well known infrastructure services — including the actual administration Console UI.
This enables:
* A development experience that mirrors mainnet, helping you build with confidence
* A smooth dev loop, from prototype to deployment
* A unique way to build, debug, and validate smart contract logic and frontend behavior — all in one place

---
## Before you begin
The emulator is a self-contained local environment that runs in a container managed entirely by Juno — using either [Docker](https://www.docker.com/) or [Podman](https://podman.io/) under the hood.
Make sure your preferred runtime is installed on your machine:
* [Docker: Windows](https://docs.docker.com/desktop/install/windows-install/)
* [Docker: macOS](https://docs.docker.com/desktop/install/mac-install/)
* [Docker: Linux](https://docs.docker.com/desktop/install/linux-install/)
* [Podman: Installation guide](https://podman.io/getting-started/installation)
**Important:**
For MacBooks with M-series processors, if you aim to use **Docker**, it is important to install Docker Desktop **version 4.25.0 or later**, ideally the latest available version.
For **Podman**, we are not aware of any particular version requirements at this time.
---
## Getting Started
To run the emulator for local development, you need to have the Juno CLI installed.
If you haven't installed it yet, run:
* npm
* yarn
* pnpm
```
npm i -g @junobuild/cli
```
```
yarn global add @junobuild/cli
```
```
pnpm add -g @junobuild/cli
```
Then, in your project folder, start the local emulator with:
```
juno emulator start
```
This will launch the emulator along with all the services needed to develop your project.
We recommend running this in a dedicated terminal window or tab, while your frontend project (e.g. using Vite or Next.js) runs separately using npm run dev or similar.
To stop the emulator, run:
```
juno emulator stop
```
**Note:**
While you could technically start the emulator using `docker run` or `podman run`, we recommend using the Juno CLI to manage the emulator lifecycle. It handles important checks, sets the correct configuration, and ensures everything runs as expected.
---
## Available Images
Juno provides two local environments. Most developers should start with **Skylab**, but Satellite is available for advanced or specialized workflows.
### 🧪 Skylab: Full Local Stack (Recommended)
The `junobuild/skylab` image is the default and recommended environment. It mirrors the production stack and includes everything needed for end-to-end development.
Use it for the full experience, including the Console UI and supporting infrastructure.
### ⚙️ Satellite: Minimal Setup
The `junobuild/satellite` image is a lightweight alternative that runs a single Satellite. It skips the Console UI and supporting infrastructure.
Use it when you need a faster, minimal setup focused on CI pipelines or automated testing.
**Note:**
The default (auto-deployed) Satellite is available with a predefined canister ID `jx5yt-yyaaa-aaaal-abzbq-cai`.
### 📊 Feature Comparison
The table below shows which modules are available in each image and helps clarify what's included when running locally with Skylab or Satellite.
| Module | Skylab | Satellite |
| --- | --- | --- |
| Console (Backend) | ✅ | ❌ |
| Console (UI) | ✅ | ❌ |
| Create Satellites / Orbiters via Console UI | ✅ | ❌ |
| Default (auto-deployed) Satellite | ❌ | ✅ |
| Observatory | ✅ | ❌ |
Likewise, not all services are mounted by default - but they can be turned on (or off).
| Service | Skylab | Satellite |
| --- | --- | --- |
| Internet Identity | ✅ | ✅ |
| ICP Ledger | ✅ | ✅ |
| ICP Index | ✅ | ✅ |
| NNS Governance | ✅ | ➖ |
| Cycles Minting (CMC) | ✅ | ➖ |
| Cycles Ledger | ✅ | ➖ |
| Cycles Index | ✅ | ➖ |
| Registry | ➖ | ➖ |
| SNS | ➖ | ➖ |
| NNS-dapp | ➖ | ➖ |
---
## Console UI
When using the `junobuild/skylab` image, the Console UI becomes available by default at:
```
http://localhost:5866/
```
Once the emulator is running (`juno emulator start`), visit this URL in your browser to explore the Console — where you can create and manage Satellites, and explore features like Datastore, Authentication, Storage, and more.
---
## Hot Reload
The local container supports live reloading. When you modify your [configuration](/docs/reference/emulator/satellite.md#configuration) or build custom [Functions](/docs/build/functions.md) to enhance Juno's capabilities with serverless features, those changes will be automatically redeployed.
---
## Configuration Options
To customize the behavior of the local emulator—such as changing ports, setting a persistent volume name, or overriding the runner image — refer to the [Emulator Configuration](/docs/reference/configuration.md#emulator-configuration) section.
There you'll find detailed information about available options including:
* ⚙️ Runner settings (e.g. image, platform, volume)
* 🔌 Custom port mappings
* 📁 Shared folders and hot reloading
* 🧪 CI and test environment tips
---
## Usage
During local development - `npm run dev` - your app connects to the local emulator (container) by default — no extra configuration needed.
### Automatic Configuration (Recommended)
The recommended way to connect your app to the local container run in the emulator or any environment is by using the [plugins](/docs/reference/plugins.md).
They automatically resolve the Satellite ID and other environment variables and handle initialization for you.
### Manual Initialization
If you're not using a plugin and are initializing Juno manually, here's how to configure it to use the local container:
```
import { initSatellite } from "@junobuild/core";const container = import.meta.env.DEV === true;await initSatellite({ satelliteId: container ? "jx5yt-yyaaa-aaaal-abzbq-cai" : "aaaaa-bbbbb-ccccc-ddddd-cai", container});
```
### Opt-out
The SDK automatically uses the emulator in local development. If you want to disable that behavior and connect directly to a remote canister (e.g. in CI or production testing), you can do:
```
await initSatellite({ satelliteId: "aaaaa-bbbbb-ccccc-ddddd-cai", container: false});
```
---
## Administration
The admin server running on port `5999` provides a variety of internal management. Below are some tips and example scripts to make use of this little server.
### Get Cycles
If you're using the full environment, the Console UI includes a "Get Cycles" button in the wallet. It's a quick way to get Cycles out of the box.

You might want to transfer some Cycles from the ledger to a specified principal, which can be particularly useful when you're just getting started developing your app and no users currently own Cycles. This can be achieved by querying:
```
http://localhost:5999/ledger/transfer/?to=$PRINCIPAL&ledgerId=um5iw-rqaaa-aaaaq-qaaba-cai&amount330000000000000
```
For example, you can use the following script:
```
#!/usr/bin/env bash# Check if a principal is passed as an argument; otherwise, prompt for itif [ -z "$1" ]; then read -r -p "Enter the Wallet ID (owner account, principal): " PRINCIPALelse PRINCIPAL=$1fi# Make a transfer request to the admin servercurl "http://localhost:5999/ledger/transfer/?to=$PRINCIPAL"
```
# Create a Satellite
When you're ready to deploy your project to production, you'll need to create a [Satellite](/docs/terminology.md#satellite).
1. To get started, sign-in to the Juno [Console](https://console.juno.build).
2. Click **Launch your first Satellite**.
3. Enter a name for your Satellite (note: this is for display purposes only and does not need to be unique).
4. Select whether you're deploying a **Website** or **Application**.
5. Confirm with **Create a Satellite.**
6. The platform will then create your Satellite and provision its resources.
7. Once the process is complete, click **Continue** to access the service page.
🎉 You’re all set! You can now deploy your frontend app, static website, or publish your serverless functions to production.
➡️ Continue with the [deployment](/docs/category/deployment.md) guides to take the next step.
---
**Note:**
Choose **Website** if you're deploying a static site, blog, portfolio, etc.
Choose **Application** if your project needs user sign-in, data management, or serverless functions.
You can change this later in your Satellite "Hosting" settings.
# Analytics
Juno Analytics, a simple, performant, and open-source analytics solution that respects your users' privacy and doesn't use cookies, ensuring anonymity while providing valuable user insights.

---
## Features
Juno Analytics offers several advantages for developers:
### 🍪 No Cookie Banners Needed
Just like all of Juno's features, Analytics prioritizes privacy. It conducts dapp and site measurements entirely anonymously, without using cookies or collecting personal data. There are no persistent identifiers, cross-site tracking, or cross-device tracking. Your analytics data is not used for any other purposes.
### ⚡️ Tiny & Blazing Fast
Juno’s analytics library is built for speed and simplicity. It’s a tiny JavaScript snippet (under 3KB gzipped) that integrates seamlessly with your application’s UI without affecting performance or boot time. This lightweight design ensures that analytics tracking won’t interfere with your user experience or your conversion rates.
### 🎯 Track What Matters
Beyond standard page views, you can gain valuable insights into your visitors by creating custom events to track conversions and attribution.
### 📣 Understand Campaign Performance
Measure the impact of your campaigns using `utm` parameters. See how people find your app — whether through ads, newsletters, or social posts — and track which sources drive the most traffic, all from your dashboard.
### 📊 Web Vitals Insights Built-In
In addition to tracking user interactions, the Analytics can also automatically collect key performance metrics using [Web Vitals](https://web.dev/articles/vitals). These metrics are essential for measuring user experience accurately, aligning with how they are captured by Chrome and reported to other Google tools. This enhancement is valuable for developers aiming to optimize the UI performance of their applications, ensuring a smoother and more responsive user experience.
### 🔍 Transparent & Open Source
Juno is fully open source, including all its Analytics features, setting it apart from proprietary tools like Google Analytics.
### 🧑🚀 Built for the Future
Unlike any other analytics alternative or solution, Juno's long-term vision is to evolve into a decentralized organization (DAO), embracing a new paradigm in the analytics industry.
---
## Considerations
In deploying Juno Analytics, it's important to understand various aspects that can affect its use and compliance.
### GDPR and PECR compliance
Juno Analytics refrains from generating persistent identifiers. It employs a random unique string to calculate unique visitor sessions on a website with each new visit.
While we are not legal experts and the responsibility for adding analytics to your project ultimately rests with you, the above approach aligns our analytics with various cookie laws and privacy regulations, including GDPR and PECR.
### Hosted on the blockchain
All tracked data is securely stored on the [Internet Computer](https://internetcomputer.org/) blockchain, without any specific geolocation by default. However, if you select a European subnet when creating the Orbiter for Analytics, your data will be stored in Europe. This gives you flexibility based on your data residency needs.
### No cross-dapp tracking
Juno Analytics does not follow users across websites and applications they visit. All data remains isolated to a single Satellite.
### You 100% own your data
As with all services provided by Juno, you are the sole controller of your containers, and your data belongs exclusively to you.
You have the capability to delete all collected data within your Analytics at any time by utilizing the [CLI](/docs/reference/cli.md).
---
## How does it work?
To gather analytics for your dapps, you need to create a module called [orbiter](/docs/terminology.md#orbiter). Creating an Orbiter requires Cycles, and its price is defined in the [transaction costs](/docs/pricing.md#transaction-costs).
Each Orbiter is used to collect analytics for one or multiple [satellites](/docs/terminology.md#satellite).
Page views are collected anonymously and saved with a unique random ID for attribution. This data is organized based on its collection timestamp.
You can also collect custom tracking events, which are organized in the same manner.
Additionally, a unique random session ID is generated for all data. Each time a visitor visits your dapps, a new session is created.
---
## Limitation
Currently, an Orbiter can store up to 500 GB of data.
**Caution:**
Similar to other analytics services, an Orbiter accepts data submitted from any source as long as the requested payload matches the expected format, and the targeted Satellite is configured to accept analytics. This is because the origin of the HTTP request cannot be accessed, for a valid reason – to prevent tracking. Therefore, calls cannot be limited to the domain of your dapps.
Consequently, this leaves the canister open to potential attacks that can pollute the data and consume cycles. For this reason, we recommend the following:
1. Avoid topping up with excessive cycles; instead, adopt a lean approach.
2. Enable [monitoring](/docs/management/monitoring.md) to ensure your modules are automatically refueled and stay online.
3. Interpret the statistics provided by this feature with some reservation, similar to any other analytics data, considering potential inaccuracies.
# Development
Learn how to track page views, custom events, and performance metrics.
---
## Page views
Page views, such as when a visitor opens your website or navigates to a subpage, are automatically tracked once you have configured, initialized, and deployed your application with the analytics module.
There's **no need** for additional development work!
However, if you (really) want to trigger page view tracking manually, you can do so using the `trackPageView()` function provided by the SDK.
```
import { trackPageView, trackPageViewAsync } from "@junobuild/analytics";trackPageView(); // or await trackPageViewAsync();
```
---
## Track custom events
Custom events can be tracked using the `trackEvent` function. You need to provide a `name` for the event, and you can include up to 10 custom `metadata` fields.
**Note:**
This is an option. As explained in the previous chapter, the library will take care of gathering insightful anonymous data as soon as it is configured and initialized.
Custom events are useful if you want to take an extra step and collect your own specific information.
Here's an example of how to use it:
```
import { trackEvent, trackEventAsync } from "@junobuild/analytics";// Fire-and-forgettrackEvent({ name: "Your custom event", metadata: { your_key: "A value", your_other_key: "Another value" }});// Or await it if neededawait trackEvent({ name: "Your custom event", metadata: { your_key: "A value", your_other_key: "Another value" }});
```
Use the `async` version if you're tracking events for which you want to absolutely ensure delivery before continuing the flow — for example, before navigating away or submitting critical user input.
That said, the tracker sends data using `keepalive` fetch requests by default, so in most cases there’s no difference in reliability — the choice is mostly a matter of convenience and flow control.
**Important:**
For scalability and optimization reasons, the data collected must adhere to certain rules, particularly regarding their length. For instance, a randomly generated key should not exceed 36 bytes in length.
For detailed information about these rules, please refer to Juno's GitHub [repository](https://github.com/junobuild/juno).
---
## Campaign tracking with UTM parameters
Juno Analytics automatically supports [UTM parameters](https://en.wikipedia.org/wiki/UTM_parameters) out of the box. These are standard query parameters (like `utm_source`, `utm_medium`, and `utm_campaign`) commonly added to links in newsletters, ads, and social posts to help you understand how visitors reach your app.
They're added to the end of a URL as query parameters. For example:
```
?utm_source=newsletter&utm_medium=email&utm_campaign=rocket-launch
```
As long as your URLs include UTM tags, campaign data will be collected and shown in your dashboard — no additional setup needed.
### Common UTM parameters
| Parameter | Required | Description | Example |
| --- | --- | --- | --- |
| `utm_source` | ✅ | Where the traffic comes from | `newsletter`, `twitter`, `github` |
| `utm_medium` | | The channel used | `email`, `social` |
| `utm_campaign` | | The name of the campaign | `rocket-launch` |
| `utm_term` | | Keywords for paid search | `juno+analytics` |
| `utm_content` | | Distinguish between different links | `header-button`, `footer-link` |
Only the `utm_source` field is mandatory. If it's missing, the campaign will not be tracked.
# Setup
This section covers how to integrate and configure Juno Analytics in your app or website.
---
## Getting Started
Before integrating Juno Analytics into your app or website, you need to create an Orbiter - the analytics container that collects anonymous usage data. Here's a step-by-step guide to get started:
1. Sign in to the Juno [Console](https://console.juno.build)
2. Navigate to [Analytics](https://console.juno.build/analytics/)
3. Click on **Get started**
4. Confirm by selecting **Create analytics**
5. (Optional) In **Advanced Options**, choose a European subnet if you want your data stored in Europe
6. Once the setup completes, click **Close** to exit the wizard
🎉 You've now created your Analytics Orbiter!
But you're not done yet — you still need to tell it which Satellites (apps) can send data.
🛠 **Final Step: Setup Tracking**
Go to the [Setup](https://console.juno.build/analytics/?tab=setup) tab in the Analytics page and select which Satellites should be allowed to track page views and events.
---
## Setup
There are two ways to integrate Juno Analytics into your project:
1. Using your favorite package manager (`npm`, `yarn`, `pnpm`). ([Learn how](#1-with-package-manager)).
2. Without installation by fetching the library from a CDN. ([Learn how](#2-from-a-cdn)).
---
### 1\. With Package Manager
Follow these steps to install and initialize the SDK using your preferred package manager.
#### Install the Library
To install the analytics library, run the following command:
* npm
* yarn
* pnpm
```
npm i @junobuild/analytics
```
```
yarn add @junobuild/analytics
```
```
pnpm add @junobuild/analytics
```
#### Configure
If you're using the [Next.js](/docs/reference/plugins.md#nextjs-plugin) or [Vite](/docs/reference/plugins.md#vite-plugin), you can define your configuration in your `juno.config` file.
juno.config.js
```
import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist" }, orbiter: { ids: { production: "aaaa-bbbbb-ccccc-ddddd-cai" // <-- Replace with your ID } }});
```
If you're not using a plugin, you can skip this step and instead provide the IDs manually when initializing the Orbiter (see next section).
#### Initialize
✅ Using plugins and config
Just call `initOrbiter()` as early as possible in your app startup:
```
import { initOrbiter } from "@junobuild/analytics";initOrbiter();
```
🛠 Without plugins
Pass your Satellite and Orbiter IDs manually:
```
import { initOrbiter } from "@junobuild/analytics";initOrbiter({ satelliteId: "<SATELLITE_ID>", // replace with your Satellite ID orbiterId: "<ORBITER_ID>" // replace with your Orbiter ID});
```
---
### 2\. From a CDN
If you don't want to - or cannot - install anything locally, you can load the SDK directly from a CDN.
Add the following script to your HTML (for example, in `index.html`). This will fetch the library from [jsDelivr](https://www.jsdelivr.com/) and start the analytics when someone loads your site:
```
<script type="module"> import { initOrbiter } from "https://cdn.jsdelivr.net/npm/@junobuild/analytics@0.2.0/+esm"; document.addEventListener( "DOMContentLoaded", () => initOrbiter({ satelliteId: "<SATELLITE_ID>", // replace with your Satellite ID orbiterId: "<ORBITER_ID>" // replace with your Orbiter ID }), { once: true } );</script>
```
---
## Optional Features
The SDK includes a few optional features you can enable to enrich your analytics. By default, these are disabled to keep your bundle small and your app fast.
---
### UA Parser
By default, the library uses a naive approach to analyze the user agent string — enough to detect general categories (like mobile vs desktop) — while keeping the bundle lean and fast.
If you need more detailed insights such as browser name, OS, or device model, you can opt in to use a full UA parser.
#### What It Adds
When enabled, the parser collects:
* Browser name and version
* Operating system
* Device type (e.g., mobile, desktop, tablet)
These enrich the stats visible in the dashboard, including OS and better browser breakdowns.
#### Why It's Opt-In
* Adds a few extra kilobytes to the app bundle
* Disabled by default to preserve performance and minimize boot time
**Note:**
A more complete UA parsing approach could be performed inside a container, but this would currently require too many resources impacting both performance and cost. Delegating it to the frontend keeps things fast and efficient.
#### How to Enable
Pass `userAgentParser: true` when calling `initOrbiter()`:
```
import { initOrbiter } from "@junobuild/analytics";initOrbiter({ options: { userAgentParser: true }});
```
---
### Performance Metrics
Juno Analytics supports tracking key performance metrics using [Web Vitals](https://github.com/GoogleChrome/web-vitals). This feature is **opt-in** and requires configuration in both the Console and your app's code.
#### Key Metrics
When enabled, the following Web Vitals are tracked:
* **Time to First Byte (TTFB)**: Measures the time it takes for the first byte of data to reach the user's browser, indicating server responsiveness.
* **First Contentful Paint (FCP)**: Marks the time when the first piece of content is rendered, helping assess initial loading speed.
* **Largest Contentful Paint (LCP)**: Tracks the time when the largest content element becomes visible, indicating when the main content is likely fully loaded.
* **Cumulative Layout Shift (CLS)**: Quantifies unexpected layout shifts during loading, reflecting visual stability.
* **Interaction to Next Paint (INP)**: Measures the latency of interactions, such as clicks, to evaluate application responsiveness.
#### How to Enable Web Vitals
To start collecting performance metrics, you need to enable it in two places:
1. **In the Console**
Go to your Orbiter's [Setup tab](https://console.juno.build/analytics/?tab=setup) and click "Edit Configuration". Enable the "Web Vitals" option under the "Advance Options" to allow the Orbiter to store performance data.
2. **In your App**
Enable Web Vitals in the SDK during initialization. This ensures that the additional logic is only loaded when needed, helping keep your app's initial load size minimal.
```
import { initOrbiter } from "@junobuild/analytics";initOrbiter({ options: { performance: true }});
```
---
## Best Practices
Here are some useful tips for working with the analytics.
### Production vs Development
While the example above shows analytics being initialized in all cases, it's recommended to **disable analytics during local development**. This prevents test data from polluting your metrics if your local environment is connected to production, and avoids errors when analytics aren't set up locally which is often the case during development.
```
if (DEV) { return;}initOrbiter();
```
### Use Environment-Specific IDs
You can also configure different IDs for different environments (e.g., development and production):
juno.config.js
```
import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { production: "qsgjb-riaaa-aaaaa-aaaga-cai" }, source: "dist" }, orbiter: { ids: { production: "aaaa-bbbbb-ccccc-ddddd-cai", development: "ffff-eeee-ddddd-ccccc-cai" } }});
```
# Authentication
Juno provides a secure, passwordless authentication framework built directly into your project. It supports multiple providers out of the box, including:
* [Google](/docs/build/authentication/google.md) - secure and familiar login
* [GitHub](/docs/build/authentication/github.md) - the login your developers already use
* [Internet Identity](/docs/build/authentication/internet-identity.md) - decentralized, privacy-preserving authentication
* [Passkeys](/docs/build/authentication/passkeys.md) - passwordless, device-native authentication using WebAuthn
It integrates seamlessly with your [Datastore](/docs/build/datastore.md) and [Storage](/docs/build/storage.md) to power the rich features you are building.
Whether you need decentralized login, device-native passkeys, or a familiar OAuth-based sign-in, Juno - by extension your project and its Satellite - handles the complexity for you so you can focus on your app instead of managing user accounts, sessions, and sensitive data.
You can view and manage your users anytime in the [Authentication](https://console.juno.build/authentication)

---
## User Identity
When someone signs in to your app, they get an identity.
That user identity is what ties them to the data they create and the actions they take.
Identities are **scoped to your app** - users can't be tracked across other sites or services.
Depending on the sign-in method and what the user consents to, your app may also receive basic profile metadata such as a name or email address.
---
## Domain-Based Identity
For privacy reasons and to prevent tracking across sites, a user's identity is tied to the domain where they sign in.
### Passkeys
With Passkeys, the identity is linked to the hostname the user signs in on. It works for that domain and its subdomains.
For example, a passkey created on `hello.com` will also work on `www.hello.com`, but not on a different domain like `world.com`.
You can change this in the sign-up options if you want it to cover a different domain than the one read from the browser's URL. For example, you may want to use the top-level domain when signing in on a subdomain. You cannot specify a totally different domain.
---
## Choosing a Provider
Each authentication method has its strengths. The right choice depends not only on your app's technical needs, but also on what your users expect and feel comfortable with.
* **Google**:
* ✅ Familiar and frictionless login with a trusted provider.
* ✅ Works across devices and browsers in all your applications.
* ✅ Supports account recovery and multi-device sync.
* 🤔 Depends on Google's infrastructure and availability.
* 🤔 Slightly higher resource usage on your Satellite and per extension costs, since it must verify tokens issued by Google and sign identities.
* **GitHub**:
* ✅ Familiar login for developer-focused apps.
* ✅ Works across devices and browsers in all your applications.
* 🤔 Requires a backend proxy to handle the OAuth flow securely.
* ⚠️ You need to self-host the [Juno API](https://github.com/junobuild/api) or run your own compatible proxy.
* **Internet Identity**:
* ✅ Fully decentralized and privacy-preserving.
* ✅ Prevents tracking between domains.
* ✅ Supports account recovery.
* 🤔 Requires a brief context switch to an external window.
* 🤔 Domain scoping requires correct configuration.
* 🤔 When users choose to sign in with a third party (Google, Apple, etc.), it also depends on their infrastructure and availability. Plus, it relies on configured credentials owned by the DFINITY Foundation.
* 🤔 Less known outside the Internet Computer ecosystem.
* **Passkeys**:
* ✅ Passwordless and device-native (Face ID, Touch ID, etc.).
* ✅ Familiar Web2-like UX with strong cryptographic security. ✅ Supports multi-device sync through password managers.
* 🤔 Users must distinguish between sign-up and sign-in flows.
* 🤔 Sync depends on Apple or Google password managers and their infrastructure.
* ⚠️ Passkeys stored locally can be lost if the browser or device is reset.
**Tip:**
Many developers combine multiple providers - for example, offering Google as the default and Internet Identity or Passkeys as alternatives.
# Local Development and E2E
Implementing Google, Internet Identity, or Passkeys requires some setup and doesn't always fit best in a local development environment or E2E test suite. For example, they take various steps to complete and therefore consume repetitive time.
Local dev identities skip all that.
They let you test authentication flows instantly - no setup, no external services, no waiting. Just one click with names like "alice" or "bob", and you're signed in.
**Caution:**
**For local development only** - works exclusively on `localhost` and `127.0.0.1`.
---
## How It Works
1. You optionally provide an identifier (e.g., "alice", "bob"). Default is "dev".
2. A deterministic identity is generated on the client side from that identifier.
3. The identifier is stored in IndexedDB and reused across sessions.
4. You can switch between different dev identities easily.
**Note:**
Given the deterministic nature of these identities, as mentioned above, they cannot be used in production. That's why the library prevents any usage outside of localhost.
---
## Sign-In
```
import { signIn } from "@junobuild/core";// ⚠️ LOCAL DEVELOPMENT ONLY - Replace with a real provider for productionawait signIn({ dev: {}});
```
---
## Options
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `identifier` | `string` | `"dev"` | Unique identifier for this dev identity (max 32 characters) |
| `maxTimeToLiveInMilliseconds` | `number` | 7 days | How long the session lasts in milliseconds |
Example:
```
// ⚠️ LOCAL DEVELOPMENT ONLY - Replace with a real provider for productionawait signIn({ dev: { identifier: "alice", maxTimeToLiveInMilliseconds: 24 * 60 * 60 * 1000 // 1 day }});
```
---
---