diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss
index 9e8405e458..672e9f1e9d 100644
--- a/assets/scss/_styles_project.scss
+++ b/assets/scss/_styles_project.scss
@@ -3365,6 +3365,10 @@ div.tablestep > table td, div.tablestep table td {
margin-left: 1.0rem;
}
+.td-content > ol li {
+ margin-bottom: 0.5rem;
+}
+
.td-content > ul {
padding-left: 1rem;
}
diff --git a/assets/tutorials/air-quality-fleet/get-readings.png b/assets/tutorials/air-quality-fleet/get-readings.png
index e637ab5270..709710c93f 100644
Binary files a/assets/tutorials/air-quality-fleet/get-readings.png and b/assets/tutorials/air-quality-fleet/get-readings.png differ
diff --git a/docs/dev/reference/changelog.md b/docs/dev/reference/changelog.md
index 185af21680..7db752194f 100644
--- a/docs/dev/reference/changelog.md
+++ b/docs/dev/reference/changelog.md
@@ -42,6 +42,13 @@ date: "2024-09-18"
# updated: "" # When the content was last entirely checked
---
+{{% changelog color="changed" title="Deprecated explicit dependencies" date="2025-05-30" %}}
+
+You can now create and use Viam applications to build custom applications that interact with your Viam-powered machines through the Viam SDKs.
+For more information, see [Viam applications](/operate/control/viam-applications/).
+
+{{% /changelog %}}
+
{{% changelog color="changed" title="Deprecated explicit dependencies" date="2025-05-05" %}}
Some older modules use "explicit dependencies" which require users to list the names of dependencies in the `depends_on` field of the resource's configuration, for example:
diff --git a/docs/operate/control/viam-applications.md b/docs/operate/control/viam-applications.md
new file mode 100644
index 0000000000..abc943c0dc
--- /dev/null
+++ b/docs/operate/control/viam-applications.md
@@ -0,0 +1,297 @@
+---
+title: "Create a Viam application"
+linkTitle: "Create a Viam application"
+weight: 5
+layout: "docs"
+type: "docs"
+description: "Create and deploy a custom web interface for your machines without managing hosting and authentication."
+---
+
+Create and deploy a custom web interface for your machines without managing hosting and authentication.
+Once deployed, your application is accessible from a dedicated URL (`appname_publicnamespace.viamapplications.com`), and hosting and authentication is handled for you.
+
+Users log into your application and select a machine they have access to.
+The application then renders your custom interface for interacting with the user's machine.
+
+{{}}
+
+## Requirements
+
+{{< expand "Install the Viam CLI and authenticate." >}}
+Install the Viam CLI using the option below that matches your system architecture:
+
+{{< readfile "/static/include/how-to/install-cli.md" >}}
+
+Then authenticate your CLI session with Viam using one of the following options:
+
+{{< readfile "/static/include/how-to/auth-cli.md" >}}
+
+{{< /expand >}}
+
+## Build a custom web interface
+
+You can build a custom web interface to access your machines using your preferred framework like React, Vue, Angular, or others.
+
+### Access machines from your application
+
+When logging into a Viam application and selecting a machine to use it with, the machine's API key is stored as a cookie.
+You can access the data from your browser's cookies as follows:
+
+````ts {class="line-numbers linkable-line-numbers" data-line=""}
+import Cookies from "js-cookie";
+
+let apiKeyId = "";
+let apiKeySecret = "";
+let hostname = "";
+let machineId = "";
+
+machineCookie = window.location.pathname.split("/")[2];
+({
+ id: apiKeyId,
+ key: apiKeySecret,
+ hostname: hostname,
+ machineId: machineId
+} = JSON.parse(Cookies.get(machineCookie)!));
+
+For developing your application on localhost, add the same information to your browser's cookies:
+
+1. Navigate to [Camera Viewer](https://camera-viewer_naomi.viamapplications.com/).
+2. Log in and select the machine you'd like to use for testing.
+3. Open Developer Tools and go to the console.
+4. Execute the following JavaScript to obtain the cookies you need:
+
+ ```js {class="line-numbers linkable-line-numbers" data-line=""}
+ function generateCookieSetterScript() {
+ // Get all cookies from current page
+ const currentCookies = document.cookie.split(";");
+ let cookieSetterCode = "// Cookie setter script for localhost\n";
+ cookieSetterCode +=
+ "// Copy and paste this entire script into your browser console when on localhost\n\n";
+
+ // Process each cookie
+ let cookieCount = 0;
+ currentCookies.forEach((cookie) => {
+ if (cookie.trim()) {
+ // Extract name and value from the cookie
+ const [name, value] = cookie.trim().split("=");
+
+ // Add code to set this cookie
+ cookieSetterCode += `document.cookie = "${name}=${value}; path=/";\n`;
+ cookieCount++;
+ }
+ });
+
+ // Add summary comment
+ cookieSetterCode += `\nconsole.log("Set ${cookieCount} cookies on localhost");\n`;
+
+ // Display the generated code
+ console.log(cookieSetterCode);
+
+ // Create a textarea element to make copying easier
+ const textarea = document.createElement("textarea");
+ textarea.value = cookieSetterCode;
+ textarea.style.position = "fixed";
+ textarea.style.top = "0";
+ textarea.style.left = "0";
+ textarea.style.width = "100%";
+ textarea.style.height = "250px";
+ textarea.style.zIndex = "9999";
+ document.body.appendChild(textarea);
+ textarea.focus();
+ textarea.select();
+ }
+
+ // Execute the function
+ generateCookieSetterScript();
+````
+
+5. Copy the resulting script. It will look like this:
+
+ ```js {class="line-numbers linkable-line-numbers" data-line=""}
+ // Cookie setter script for localhost
+ // Copy and paste this entire script into your browser console when on localhost
+
+ document.cookie = "; path=/";
+ document.cookie = "machinesWhoseCredentialsAreStored=; path=/";
+
+ console.log("Set 2 cookies on localhost");
+ ```
+
+6. Open the application you are building on localhost and run the resulting script.
+7. Reload your application.
+
+### Configure routing
+
+When using your deployed application, static files will be accessible at `https://your-app-name_your-public-namespace.viamapplications.com/machine//`.
+If your HTML file loads other files, use relative paths to ensure your files are accessible.
+
+## Deploy your web interface as a Viam application
+
+To deploy your application with Viam you must package it as a module and upload it using the Viam CLI.
+
+{{< table >}}
+{{% tablestep number=1 %}}
+
+**Create a meta.json** file for your module using this template:
+
+{{< tabs >}}
+{{% tab name="Template" %}}
+
+```json
+{
+ "module_id": "your-namespace:your-module",
+ "visibility": "public",
+ "url": "https://github.com/your-org/your-repo",
+ "description": "Your module description",
+ "applications": [
+ {
+ "name": "your-app-name",
+ "type": "single_machine",
+ "entrypoint": "dist/index.html"
+ }
+ ]
+}
+```
+
+{{% /tab %}}
+{{% tab name="Example" %}}
+
+```json
+{
+ "module_id": "acme:dashboard",
+ "visibility": "public",
+ "url": "https://github.com/acme/dashboard",
+ "description": "An example dashboard for a fictitious company called Acme.",
+ "applications": [
+ {
+ "name": "dashboard",
+ "type": "single_machine",
+ "entrypoint": "dist/index.html"
+ }
+ ]
+}
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+This file specifies the contents of the module.
+It is required for your module.
+
+{{% expand "Click to view more information on attributes." %}}
+
+
+| Name | Type | Inclusion | Description |
+|------|------|-----------|-------------|
+| `module_id` | string | **Required** | The module ID, which includes the organization name and the module name. `module_id` uniquely identifies your module. |
+| `visibility` | string | **Required** | Must be `"public"`. |
+| `description` | string | **Required** | A description of your module and what it provides. |
+| `url` | string | Optional | The URL of the GitHub repository containing the source code of the module. |
+| `applications` | array | Optional | Objects that provide information about the [applications](/operate/control/viam-applications/) associated with the module. |
+| `models` | array | Optional | Empty unless you are shipping the app alongside models. For information on how to add models, see [Integrate other hardware](/operate/get-started/other-hardware/). |
+
+{{% /expand%}}
+
+The `applications` field is an array of application objects with the following properties:
+
+
+| Property | Type | Description |
+| ------------ | ------ | ----------- |
+| `name` | string | The name of your application, which will be a part of the application's URL (`name_publicnamespace.viamapplications.com`). For more information on valid names see [Valid application identifiers](/operate/reference/naming-modules/#valid-application-identifiers). |
+| `type` | string | The type of application (currently only `"single_machine"` is supported). |
+| `entrypoint` | string | The path to the HTML entry point for your application. The `entrypoint` field specifies the path to your application's entry point. For example: "dist/index.html"
: Static content rooted at the `dist` directory"dist/foo.html"
: Static content rooted at the `dist` directory, with `foo.html` as the entry point"dist/"
: Static content rooted at the `dist` directory (assumes `dist/index.html` exists)"dist/bar/foo.html"
: Static content rooted at `dist/bar` with `foo.html` as the entry point
|
+
+{{% /tablestep %}}
+{{% tablestep number=2 %}}
+**Register your module** with Viam:
+
+{{< tabs >}}
+{{% tab name="Template" %}}
+
+```sh {class="command-line" data-prompt="$" data-output="3-10"}
+viam module create --name="app-name" --public-namespace="namespace"
+```
+
+{{% /tab %}}
+{{% tab name="Example" %}}
+
+```sh {class="command-line" data-prompt="$" data-output="3-10"}
+viam module create --name="air-quality" --public-namespace="naomi"
+```
+
+{{% /tab %}}
+{{< /tabs >}}
+
+{{% /tablestep %}}
+{{% tablestep number=3 %}}
+
+**Package your static files and your meta.json file and upload them** to the Viam Registry:
+
+```sh {class="command-line" data-prompt="$" data-output="3-10"}
+tar -czvf module.tar.gz meta.json
+viam module upload --upload=module.tar.gz --platform=any --version=0.0.1
+```
+
+For subsequent updates run these commands again with an updated version number.
+
+{{% /tablestep %}}
+{{< /table >}}
+
+## Access your application
+
+After uploading your module with the application configuration, your application will be available at:
+
+```txt
+https://your-app-name_your-public-namespace.viamapplications.com
+```
+
+Users will be prompted to authenticate with their Viam credentials before accessing your application:
+
+1. User navigates to `your-app-name_your-public-namespace.viamapplications.com`.
+1. User authenticates with Viam credentials.
+1. User selects an organization, location, and machine.
+1. User is redirected to `your-app-name_your-public-namespace.viamapplications.com/machine/{machine-id}`.
+1. Your application is rendered with access to the selected machine.
+
+## Example
+
+
+
+For a React application that shows camera feeds for a machine, see [Viam Camera Viewer](https://github.com/viam-labs/viam-camera-viewer).
+
+## Limitations
+
+- Applications currently only support single-machine applications.
+- All modules with applications must have public visibility.
+- The page will always render the latest version.
+- Browsers with cookies disabled are not supported.
+- Viam applications serve static files.
+ If you are building an application with server-side rendering or need other back-end capabilites, Viam applications is not the right choice.
+
+## Security considerations
+
+- Customer applications are stored publicly on the internet, so avoid uploading sensitive information in your application code or assets.
+- API keys and secrets are stored in the browser's cookies.
+- Users authenticate with FusionAuth.
+
+## FAQ
+
+### Can I use a custom domain?
+
+If you want to serve your side from a domain other than `your-app-name_your-public-namespace.viamapplications.com`, you can set this up with your DNS provider.
+
+To configure an apex domain (`example.com`) and the `www` subdomain, set the following values:
+
+
+| Domain | DNS record type | DNS record name | DNS record value |
+| ------ | --------------- | --------------- | ---------------- |
+| `example.com` | `A` | `@` | `34.8.79.17` |
+| `example.com` | `ANAME` or `ALIAS` | `@` | `your-app-name_your-public-namespace.viamapplications.com` |
+| `www.examples.com` | `CNAME` | `SUBDOMAIN.example.com` | `your-app-name_your-public-namespace.viamapplications.com` |
+
+To configure a subdomain, set the following values:
+
+
+| Domain | DNS record type | DNS record name | DNS record value |
+| ------ | --------------- | --------------- | ---------------- |
+| Subdomain (`www.examples.com` or `app.example.com`) | `CNAME` | `SUBDOMAIN.example.com` | `your-app-name_your-public-namespace.viamapplications.com` |
diff --git a/docs/operate/control/web-app.md b/docs/operate/control/web-app.md
index 602a588420..500c72a2ad 100644
--- a/docs/operate/control/web-app.md
+++ b/docs/operate/control/web-app.md
@@ -13,6 +13,11 @@ The TypeScript SDK includes:
- Implementation of the standard component and service APIs to control your hardware and software
- Authentication tools so users can log in securely
+{{< alert title="Tip: Host your application on Viam" color="tip" >}}
+You can host most apps by [deploying them as Viam applications](/operate/control/viam-applications/).
+If your application requires server-side rendering or other back-end functionality, self-host your application instead.
+{{< /alert >}}
+
## Install the TypeScript SDK
Run the following command in your terminal to install the Viam TypeScript SDK:
diff --git a/docs/operate/get-started/other-hardware/_index.md b/docs/operate/get-started/other-hardware/_index.md
index efd365648a..0381b23d3f 100644
--- a/docs/operate/get-started/other-hardware/_index.md
+++ b/docs/operate/get-started/other-hardware/_index.md
@@ -987,16 +987,16 @@ Do not change the module_id
.
models |
-object |
-Required |
-A list of one or more {{< glossary_tooltip term_id="model" text="models" >}} provided by your custom module. You must provide at least one model, which consists of an api and model key pair. If you are publishing a public module ("visibility": "public" ), the namespace of your model must match the namespace of your organization.
+ | array |
+Optional |
+A list of one or more {{< glossary_tooltip term_id="model" text="models" >}} provided by your custom module. You must provide at least one model in the models array or one application in the applications array. A model consists of an api and model key pair. If you are publishing a public module ("visibility": "public" ), the namespace of your model must match the namespace of your organization.
You are strongly encouraged to include a markdown_link to the section of the README containing configuration information about each model, so that the section will be displayed alongside the configuration panel when configuring the model. For example, "README.md#configure-your-meteo_pm-sensor" . Please also include a short_description describing what hardware the model supports. |
entrypoint |
string |
-Required |
-The name of the file that starts your module program. This can be a compiled executable, a script, or an invocation of another program. If you are providing your module as a single file to the upload command, provide the path to that single file. If you are providing a directory containing your module to the upload command, provide the path to the entry point file contained within that directory. |
+Optional |
+The name of the file that starts your module program. This can be a compiled executable, a script, or an invocation of another program. If you are providing your module as a single file to the upload command, provide the path to that single file. If you are providing a directory containing your module to the upload command, provide the path to the entry point file contained within that directory. Required if you are shipping a model. |
build |
@@ -1016,6 +1016,12 @@ Do not change the module_id
.
Optional |
Enables VS Code hover and autocomplete as you edit your module code. Gets auto-generated when you run viam module generate or viam module create . Has no impact on the module's function. |
+
+applications |
+array |
+Optional |
+Objects that provide information about the [applications](/operate/control/viam-applications/) provided by the module. |
+
diff --git a/docs/operate/reference/module-configuration.md b/docs/operate/reference/module-configuration.md
index fba7b1288f..7314146bab 100644
--- a/docs/operate/reference/module-configuration.md
+++ b/docs/operate/reference/module-configuration.md
@@ -227,6 +227,64 @@ For any version type other than **Patch (X.Y.Z)**, the module will upgrade as so
If, for example, the module provides a motor component, and the motor is running, it will stop while the module upgrades.
{{% /alert %}}
+### Module meta.json configuration
+
+When creating a module, you'll need to create a `meta.json` file that defines the module's properties. This file includes information about the module's ID, visibility, models, and other features.
+
+Here's an example of a `meta.json` file:
+
+```json
+{
+ "module_id": "your-namespace:your-module",
+ "visibility": "public",
+ "url": "https://github.com/your-org/your-repo",
+ "description": "Your module description",
+ "models": [
+ {
+ "api": "rdk:component:base",
+ "model": "your-namespace:your-module:your-model"
+ }
+ ],
+ "entrypoint": "run.sh",
+ "first_run": "setup.sh"
+}
+```
+
+For modules that include [Viam applications](/operate/control/viam-applications/), you can add the `applications` field:
+
+```json
+{
+ "module_id": "your-namespace:your-module",
+ "visibility": "public",
+ "url": "https://github.com/your-org/your-repo",
+ "description": "Your module description",
+ "models": [
+ {
+ "api": "rdk:component:base",
+ "model": "your-namespace:your-module:your-model"
+ }
+ ],
+ "entrypoint": "run.sh",
+ "applications": [
+ {
+ "name": "your-app-name",
+ "type": "web",
+ "entrypoint": "dist/index.html"
+ }
+ ]
+}
+```
+
+The `applications` field is an array of application objects with the following properties:
+
+| Property | Type | Description |
+| ------------ | ------ | ------------------------------------------------------------------------------------------------- |
+| `name` | string | The name of your application, which will be used in the URL (`name.publicnamespace.viamapps.com`) |
+| `type` | string | The type of application (currently only `"web"` is supported) |
+| `entrypoint` | string | The path to the HTML entry point for your application |
+
+For more information about Viam applications, see the [Viam applications documentation](/operate/control/viam-applications/).
+
### Environment variables
Each module has access to the following default environment variables.
diff --git a/docs/operate/reference/naming-modules.md b/docs/operate/reference/naming-modules.md
index bd544e60e1..d1ef3cbcf8 100644
--- a/docs/operate/reference/naming-modules.md
+++ b/docs/operate/reference/naming-modules.md
@@ -9,7 +9,7 @@ description: "Add support for a new component or service model by writing a modu
languages: ["c++"]
viamresources: []
platformarea: ["registry"]
-toc_hide: true
+toc_hide: false
---
Each modular resource has two associated triplets: an API namespace triplet to indicate which [API](/dev/reference/apis/) it implements, and a model namespace triplet to uniquely identify the modular resource {{< glossary_tooltip term_id="model" text="model" >}}.
@@ -95,6 +95,30 @@ More requirements:
Determine the model name you want to use based on these requirements, then proceed to the next section.
+## Valid application identifiers
+
+If your module includes a [Viam app](/operate/control/viam-app/), you need to define the application name in your module's `meta.json` file.
+Application names have the following requirements:
+
+- Application names must be all-lowercase.
+- Application names may only use alphanumeric (`a-z` and `0-9`) and hyphen (`-`) characters.
+- Application names may not start or end with a hyphen.
+- Application names must be unique within your organization's namespace.
+
+The URL for accessing your Viam app will contain your application name:
+
+```txt
+https://app-name_your-public-namespace.viamapps.com
+```
+
+For example, if your organization namespace is `acme` and your application name is `dashboard`, your application will be accessible at:
+
+```txt
+https://dashboard_acme.viamapps.com
+```
+
+For more information about Viam apps, see the [Viam apps documentation](/operate/control/viam-app/).
+
## Create a namespace for your organization
When uploading modules to the Viam Registry, you must set a unique namespace for your organization to associate your module with.
diff --git a/netlify.toml b/netlify.toml
index 731a04e3d0..05f81d62a3 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -57,7 +57,7 @@
[plugins.inputs]
# change this key to a new one any time you need to restart from scratch
- cacheKey = ["May022025"]
+ cacheKey = ["Jul042025"]
# either "warn" or "error"
failBuildOnError = true
diff --git a/static/spa.mp4 b/static/spa.mp4
new file mode 100644
index 0000000000..8704d06d6c
Binary files /dev/null and b/static/spa.mp4 differ
diff --git a/static/spa.webm b/static/spa.webm
new file mode 100644
index 0000000000..49caed05ed
Binary files /dev/null and b/static/spa.webm differ