-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathllms-full.txt
More file actions
11823 lines (7080 loc) · 532 KB
/
llms-full.txt
File metadata and controls
11823 lines (7080 loc) · 532 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.
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 ICP
If you're using the full environment, the Console UI includes a "Get ICP" button in the wallet. It's a quick way to get ICP out of the box.

You might want to transfer some ICP 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 ICP. This can be achieved by querying:
```
http://localhost:5999/ledger/transfer/?to=$PRINCIPAL
```
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). If you are a new developer on Juno and the Internet Computer, you may be prompted to create your first anonymous [Internet Identity](/docs/terminology.md#internet-identity).
2. Click **Launch a new satellite**.
3. Enter a name for your satellite (note: this is for display purposes only and does not need to be unique).
4. Confirm with **Create a Satellite.**
5. The platform will then create your satellite and provision its resources.
6. Once the process is complete, click **Continue** to access the overview 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.
# 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" } }});
```
# Google
Google Sign-In lets users authenticate with their existing Google account using OpenID Connect (OIDC) - a modern, secure identity standard built on top of OAuth 2.0.
This provides a fast and familiar experience for users, without you having to manage passwords or credentials directly.
It's the easiest way to onboard users who expect a simple, frictionless login flow that works across devices and browsers.
---
## How It Works
1. The user signs in with Google.
2. Google verifies their credentials and issues a signed OpenID Connect token.
3. Your Satellite verifies the token and its signature, and extracts the user's information (such as email or profile).
4. It then establishes a session for the user.
**Note:**
Google authentication is not domain-scoped. Users keep the same identity across all your apps each time you use the same Google Client ID.
---
## Configuration
To enable Google authentication for your project:
### 1\. Get your Google credentials
Start by creating your Google credentials.
It's best to use a separate Google Cloud project for each environment (development, staging, production) so you can keep configurations clean and secure.
1. Go to the [Google Cloud Console](https://console.cloud.google.com/apis/dashboard).
2. Create a new project (or select one for your current environment). You might need to switch to your newly created project after creating it.
3. If you created a new project, configure the OAuth consent screen with information about your app. Click Configure consent screen when prompted.
4. Open **APIs & Services → Credentials**.
5. Click **Create Credentials → OAuth Client ID**.
6. Select **Web application** as the application type.
Then, configure your redirect URIs.
For local development, you can use something like `http://localhost:3000/auth/callback/google`. In production, use the URL that matches your deployed app, for example `https://example.com/auth/callback/google`.
The exact redirect path depends on how your app handles authentication, but make sure you always set at least one redirect URI in your Google Console.
**Caution:**
Creating a separate OAuth 2.0 Client ID for each environment and always configuring **Authorized redirect URIs** is a must.
Since the Client ID is public, leaving redirect URIs open could let attackers interfere with your authentication flow. Likewise, keeping a localhost URL alongside your production redirect is also a security risk.
It's also recommended to set Authorized JavaScript origins, which will be used once FedCM (Federated Credential Management) support is added.
### 2\. Configure the provider
Once your credentials are ready, you need to add your Google Client ID to your project configuration.
In your `juno.config` file:
```
import { defineConfig } from "@junobuild/config";export default defineConfig({ satellite: { ids: { development: "<DEV_SATELLITE_ID>", production: "<PROD_SATELLITE_ID>" }, source: "dist", authentication: { google: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com" } } }});
```
If you use different Client IDs for each environment (as recommended), you can leverage the build mode to load configuration conditionally.
For example, to enable Google Sign-In only in production:
```
import { defineConfig } from "@junobuild/config";export default defineConfig(({ mode }) => ({ satellite: { ids: { development: "<DEV_SATELLITE_ID>", production: "<PROD_SATELLITE_ID>" }, source: "dist", ...(mode === "production" && { authentication: { google: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com" } } }) }}));
```
### 3\. Apply the configuration
Once your credentials are set in `juno.config`, you need to make sure both your frontend and your Satellite are using the correct and same Google Client ID.
#### Frontend
The frontend, your application, needs the Client ID to start the sign-in flow.
If you are using the Juno Vite or Next.js plugin, the configuration is read automatically from `juno.config`, so you do not need to do anything. The Client ID is injected at build time.
If you are not using a plugin, you need to pass the Client ID manually, either from your environment variables or directly in the sign-in call (see ([Options](#options))).
#### Backend
Your Satellite also needs the Client ID because it is used to validate the JWT tokens issued during the sign-in flow with the third party provider in this case Google.
You can configure this in two ways:
* **Through the Console:**
Go to [console.juno.build](https://console.juno.build), select your Satellite, then open **Authentication → Setup** and enable **Google**.
The wizard will ask for your Client ID and enable the provider.
* **Through the CLI:**
If you already have the CLI installed and since the Client ID has been defined in your `juno.config`, you can apply the configuration directly with:
```
juno config apply
```
By default, this applies the production configuration. You can specify another mode using `--mode` argument if needed.
---
## Sign-In
Once your configuration is ready, you can let users sign in with their Google account.
```
import { signIn } from "@junobuild/core";await signIn({ google: {}});
```
This starts the standard Google redirect flow.
After the user authenticates, they should be redirected to the URL you configured as an Authorized redirect URI in the Google Cloud Console.
You can pass this URL through the `redirectUrl` option. If you omit it, the current origin (`window.location.origin`) is used.
### Options
Google sign-in supports a few options that let you control scopes, redirect URLs, and the overall sign-in experience.
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `clientId` | `string` | from `juno.config` | Your Google OAuth Client ID. If not provided, it is automatically read from your project configuration using the plugins. |
| `redirectUrl` | `string` | `window.location.origin` | The URL where the user is redirected after sign-in. It must match one of your authorized redirect URIs in the Google Cloud Console. |
| `authScopes` | `GoogleAuthScopes` | `['openid', 'profile', 'email']` | OAuth scopes to request. Must include `openid` and at least one of `profile` or `email`. |
| `loginHint` | `string` | | Optional hint such as an email address that tells Google which user is likely signing in. Helps skip the account picker for known users. |
Example:
```
import { signIn } from "@junobuild/core";await signIn({ google: { redirect: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com", authScopes: ["openid", "email"], redirectUrl: "https://example.com/auth/callback/google", loginHint: "user@example.com" } }});
```
---
## Handling the Redirect
After authentication, Google redirects the user back to your app with a signed token. You must handle that redirect on the route that matches your configured `redirectUrl`. For example, `/auth/callback/google`.
```
import { handleRedirectCallback } from "@junobuild/core";await handleRedirectCallback();
```
If the callback is successful, the user is signed in and a session is created.
**Tip:**
After handling the redirect, it's best to navigate elsewhere in your app without keeping browser history. This prevents the user from re-triggering authentication when pressing the back button.
---
## Advanced Configuration
You can optionally configure how authentication sessions behave on your Satellite.
These settings can be defined in your `juno.config` file and applied with `juno config apply` or adjusted directly in the Console under **Authentication → Setup**.
### Delegation
The `delegation` section defines how long sessions last and which modules authenticated users are allowed to call using their active session.
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `allowedTargets` | `PrincipalText[]` or `null` | restricted to this Satellite | List of modules (canisters on the Internet Computer) that authenticated users may call. Omit to restrict access to this Satellite only. Provide an array to allow calls only to specific targets. Set to `null` to allow calls to **any** backend (**use with caution**). |
| `sessionDuration` | `bigint` | 1 day | How long a user session remains valid, expressed in **nanoseconds**. Cannot exceed 30 days. Applies only to new sessions. |
Example configuration:
```
authentication: { google: { clientId: "1234567890-abcde12345fghijklmno.apps.googleusercontent.com" }, delegation: { allowedTargets: ["<YOUR_SATELLITE_ID>", "<LEDGER_CANISTER_ID>"], sessionDuration: BigInt(7 * 24 * 60 * 60 * 1_000_000_000) // 7 days }}
```
---
## Recommendations
* ⚠️ Always configure **Authorized redirect URIs** in the Google Cloud Console.
* Use a separate **OAuth Client ID** for each environment (development, staging, production).
* Keep your frontend and Satellite **Client IDs** in sync.
* Do not leave a **localhost URI** next to production URIs in the same Client ID.
* In the future, Juno will support **FedCM (Federated Credential Management)** for Google Sign-In without redirects.
---
---
## Infrastructure Overview
When you enable Google Sign-In, authentication involves two systems: Google and your Satellite.
Google handles the user-facing part — displaying the sign-in screen and issuing a signed OpenID Connect (OIDC) token once the user authenticates.
From there, everything else runs within your Satellite container:
* The Satellite verifies the token's signature.
* It prepares and signs a delegation identity that represents the authenticated user session.
* It creates (or retrieves) the user entry that your app can then use with Juno services such as [Datastore](/docs/build/datastore.md) and [Storage](/docs/build/storage.md).
### Token Verification
OIDC tokens are signed by Google using rotating public keys (JWKS). Therefore, to verify these signatures, Satellites need access to those keys.
Instead of having each Satellite perform HTTPS outcalls to Google — which would add cost and subnet load — Juno provides these keys through a shared infrastructure module called [Observatory](/docs/miscellaneous/architecture.md#observatory).
Observatory regularly fetches and caches Google's public keys, ensuring that verification inside your Satellite remains fast and reliable without introducing additional overhead.
This setup means your Satellite **trusts Juno** to deliver the correct, untempered, up-to-date keys.
If you prefer to control this part as well, or if you want to improve redundancy in your setup while taking care of the related cost, you can spin your own Observatory instance. Reach out if you're interested in setting that up.
# Internet Identity
[Internet Identity](https://identity.ic0.app) lets users authenticate securely and anonymously through a decentralized identity system built for the Internet Computer.
When a user signs in with Internet Identity, they confirm their identity through the provider. If successful, a session is created automatically and the user can interact with your satellite.
Authentication with Internet Identity offers strong privacy guarantees and complete isolation between domains by design.
---
## How It Works
1. The user signs in via Internet Identity.
2. The provider issues a unique, domain-specific pseudonymous identity.
3. Your project associates that identity with the user's data in your Satellite.
4. The user can immediately start using your app - no email, passwords, or extra setup.
---
---
## Example
```
import { signIn } from "@junobuild/core";await signIn({ internet_identity: {}});
```
This creates (or reuses) a session automatically the first time the user signs in.