> ## Documentation Index
> Fetch the complete documentation index at: https://docs.velatir.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Enterprise Deployment

> Roll Velatir for Desktop out across your fleet with Microsoft Intune, Jamf Pro, or any MDM

export const DesktopInstallGenerator = () => {
  const [ingestKey, setIngestKey] = useState("");
  const [os, setOs] = useState("windows");
  const [arch, setArch] = useState("x64");
  const [copied, setCopied] = useState("");
  const cleanArg = value => value.trim().replace(/"/g, "");
  const typedKey = cleanArg(ingestKey);
  const hasKey = typedKey.length > 0;
  const key = typedKey || "vltr_ingest_yourIngestKeyHere";
  const isWindows = os === "windows";
  const file = isWindows ? `Velatir-Bootstrap-${arch}.msi` : `Velatir-Bootstrap-macos-${arch}.pkg`;
  const downloadUrl = isWindows ? `https://releases.velatir.com/velatir-desktop/windows-${arch}/latest/${file}` : `https://releases.velatir.com/velatir-desktop/macos-${arch}/latest/${file}`;
  const command = isWindows ? `msiexec /i ${file} INGEST_KEY="${key}" /qn` : `sudo installer -pkg ${file} -target /`;
  const intuneArgs = `/qn INGEST_KEY="${key}"`;
  const setKeyCommand = `sudo velatir set-api-key --key ${key}`;
  const archOptions = isWindows ? [{
    value: "x64",
    label: "x64"
  }, {
    value: "arm64",
    label: "arm64"
  }] : [{
    value: "arm64",
    label: "Apple Silicon"
  }, {
    value: "x64",
    label: "Intel"
  }];
  const selectOs = value => {
    setOs(value);
    setArch(value === "windows" ? "x64" : "arm64");
  };
  const copy = async (text, which) => {
    try {
      await navigator.clipboard.writeText(text);
      setCopied(which);
      setTimeout(() => setCopied(""), 2000);
    } catch (e) {}
  };
  const escapeXml = value => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
  const downloadText = (content, filename, mime) => {
    const blob = new Blob([content], {
      type: mime
    });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = filename;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  };
  const apiKeyMobileconfig = () => `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>PayloadIdentifier</key>
    <string>com.velatir.desktopapp.mdm</string>
    <key>PayloadUUID</key>
    <string>6F2A8B14-9C3E-4D71-A5B8-1E7C4D9F2A60</string>
    <key>PayloadDisplayName</key>
    <string>Velatir Desktop Agent</string>
    <key>PayloadDescription</key>
    <string>Provisions the Velatir agent's ingest key.</string>
    <key>PayloadOrganization</key>
    <string>Velatir</string>
    <key>PayloadScope</key>
    <string>System</string>
    <key>PayloadContent</key>
    <array>
        <dict>
            <key>PayloadType</key>
            <string>com.apple.ManagedClient.preferences</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <key>PayloadIdentifier</key>
            <string>com.velatir.desktopapp.mdm.preferences</string>
            <key>PayloadUUID</key>
            <string>6F2A8B14-9C3E-4D71-A5B8-1E7C4D9F2A61</string>
            <key>PayloadDisplayName</key>
            <string>Velatir Agent Configuration</string>
            <key>PayloadContent</key>
            <dict>
                <key>com.velatir.agent</key>
                <dict>
                    <key>Forced</key>
                    <array>
                        <dict>
                            <key>mcx_preference_settings</key>
                            <dict>
                                <key>ApiKey</key>
                                <string>${escapeXml(key)}</string>
                            </dict>
                        </dict>
                    </array>
                </dict>
            </dict>
        </dict>
    </array>
</dict>
</plist>
`;
  const loginItemsMobileconfig = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>PayloadIdentifier</key>
    <string>com.velatir.desktopapp.loginitems</string>
    <key>PayloadUUID</key>
    <string>3C9E7A12-8B4F-4D6A-9E21-5F80C4B7A301</string>
    <key>PayloadDisplayName</key>
    <string>Velatir Background Items</string>
    <key>PayloadOrganization</key>
    <string>Velatir</string>
    <key>PayloadScope</key>
    <string>System</string>
    <key>PayloadContent</key>
    <array>
        <dict>
            <key>PayloadType</key>
            <string>com.apple.servicemanagement</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <key>PayloadIdentifier</key>
            <string>com.velatir.desktopapp.loginitems.rules</string>
            <key>PayloadUUID</key>
            <string>3C9E7A12-8B4F-4D6A-9E21-5F80C4B7A302</string>
            <key>PayloadDisplayName</key>
            <string>Velatir Managed Login Items</string>
            <key>Rules</key>
            <array>
                <dict>
                    <key>RuleType</key>
                    <string>TeamIdentifier</string>
                    <key>RuleValue</key>
                    <string>AA7QLU3S4R</string>
                    <key>Comment</key>
                    <string>Velatir agent and host background items</string>
                </dict>
            </array>
        </dict>
    </array>
</dict>
</plist>
`;
  const notificationsMobileconfig = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>PayloadIdentifier</key>
    <string>com.velatir.desktopapp.notifications</string>
    <key>PayloadUUID</key>
    <string>4D0F8B23-9C5A-4E7B-A032-6A91D5C8B401</string>
    <key>PayloadDisplayName</key>
    <string>Velatir Notifications</string>
    <key>PayloadOrganization</key>
    <string>Velatir</string>
    <key>PayloadScope</key>
    <string>System</string>
    <key>PayloadContent</key>
    <array>
        <dict>
            <key>PayloadType</key>
            <string>com.apple.notificationsettings</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <key>PayloadIdentifier</key>
            <string>com.velatir.desktopapp.notifications.settings</string>
            <key>PayloadUUID</key>
            <string>4D0F8B23-9C5A-4E7B-A032-6A91D5C8B402</string>
            <key>PayloadDisplayName</key>
            <string>Velatir Notification Settings</string>
            <key>NotificationSettings</key>
            <array>
                <dict>
                    <key>BundleIdentifier</key>
                    <string>com.velatir.desktopapp</string>
                    <key>NotificationsEnabled</key>
                    <true/>
                    <key>AlertType</key>
                    <integer>2</integer>
                    <key>ShowInNotificationCenter</key>
                    <true/>
                    <key>ShowInLockScreen</key>
                    <true/>
                    <key>BadgesEnabled</key>
                    <true/>
                    <key>SoundsEnabled</key>
                    <true/>
                    <key>CriticalAlertEnabled</key>
                    <false/>
                </dict>
            </array>
        </dict>
    </array>
</dict>
</plist>
`;
  const labelStyle = {
    display: "block",
    fontWeight: 600,
    fontSize: "14px",
    marginBottom: "2px"
  };
  const inputStyle = {
    width: "100%",
    boxSizing: "border-box",
    padding: "8px 12px",
    border: "1px solid rgba(128,128,128,0.4)",
    borderRadius: "8px",
    background: "transparent",
    color: "inherit",
    fontSize: "14px",
    marginTop: "4px"
  };
  const toggleButton = active => ({
    padding: "8px 16px",
    borderRadius: "8px",
    border: active ? "1px solid #F74F4F" : "1px solid rgba(128,128,128,0.4)",
    background: active ? "#F74F4F" : "transparent",
    color: active ? "#fff" : "inherit",
    fontWeight: 600,
    fontSize: "14px",
    cursor: "pointer"
  });
  const codeBox = {
    display: "block",
    width: "100%",
    boxSizing: "border-box",
    padding: "12px 14px",
    border: "1px solid rgba(128,128,128,0.3)",
    borderRadius: "8px",
    background: "rgba(128,128,128,0.08)",
    fontFamily: "monospace",
    fontSize: "13px",
    whiteSpace: "pre-wrap",
    wordBreak: "break-all",
    margin: 0
  };
  const copyButton = {
    padding: "6px 14px",
    borderRadius: "8px",
    border: "1px solid #F74F4F",
    background: "transparent",
    color: "#F74F4F",
    fontWeight: 600,
    fontSize: "13px",
    cursor: "pointer",
    marginTop: "8px"
  };
  const filledButton = enabled => ({
    padding: "6px 14px",
    borderRadius: "8px",
    border: "none",
    background: "#F74F4F",
    color: "#fff",
    fontWeight: 600,
    fontSize: "13px",
    cursor: enabled ? "pointer" : "not-allowed",
    opacity: enabled ? 1 : 0.5,
    marginTop: "8px"
  });
  const helpText = {
    fontSize: "13px",
    opacity: 0.75,
    margin: "8px 0 0"
  };
  const innerPanel = {
    border: "1px solid rgba(128,128,128,0.3)",
    borderRadius: "10px",
    padding: "14px"
  };
  const fleetKeySection = <div style={innerPanel}>
      <label style={labelStyle}>Ingest key profile</label>
      <p style={{
    ...helpText,
    marginTop: "4px"
  }}>
        Intune: <strong>Devices → Configuration → Create → Templates → Custom</strong>, upload the <code style={{
    fontFamily: "monospace"
  }}>.mobileconfig</code>. Jamf: upload the same file, or Application & Custom Settings → <code style={{
    fontFamily: "monospace"
  }}>ApiKey</code>.
      </p>
      <div style={{
    display: "flex",
    gap: "10px",
    flexWrap: "wrap",
    alignItems: "center"
  }}>
        <button type="button" disabled={!hasKey} onClick={() => downloadText(apiKeyMobileconfig(), "velatir-desktop-agent.mobileconfig", "application/x-apple-aspen-config")} style={filledButton(hasKey)}>
          .mobileconfig
        </button>
      </div>
      {!hasKey && <p style={{
    fontSize: "12px",
    opacity: 0.6,
    margin: "6px 0 0"
  }}>
          Enter an ingest key above to enable these. The key never leaves this browser.
        </p>}
    </div>;
  const quietProfilesSection = <div style={innerPanel}>
      <label style={labelStyle}>Quiet-install profiles</label>
      <p style={{
    ...helpText,
    marginTop: "4px"
  }}>
        Optional. Assign first, same Macs as the package.
      </p>
      <div style={{
    display: "flex",
    gap: "10px",
    flexWrap: "wrap",
    alignItems: "center"
  }}>
        <button type="button" onClick={() => downloadText(loginItemsMobileconfig, "velatir-background-items.mobileconfig", "application/x-apple-aspen-config")} style={copyButton}>
          Background items
        </button>
        <button type="button" onClick={() => downloadText(notificationsMobileconfig, "velatir-notifications.mobileconfig", "application/x-apple-aspen-config")} style={copyButton}>
          Notifications
        </button>
      </div>
    </div>;
  return <div style={{
    border: "1px solid rgba(128,128,128,0.3)",
    borderRadius: "12px",
    padding: "20px",
    margin: "16px 0"
  }}>
      <div style={{
    marginBottom: "14px"
  }}>
        <label style={labelStyle}>Ingest key</label>
        <input type="text" value={ingestKey} onChange={e => setIngestKey(e.target.value)} placeholder="vltr_ingest_..." autoComplete="off" spellCheck={false} style={{
    ...inputStyle,
    fontFamily: "monospace"
  }} />
        <p style={{
    fontSize: "13px",
    opacity: 0.7,
    margin: "6px 0 0"
  }}>
          The ingest key maps each machine's traces to your organisation.
        </p>
      </div>

      <div style={{
    marginBottom: "14px"
  }}>
        <label style={labelStyle}>Platform</label>
        <div style={{
    display: "flex",
    gap: "8px",
    marginTop: "4px"
  }}>
          <button type="button" onClick={() => selectOs("windows")} style={toggleButton(isWindows)}>Windows</button>
          <button type="button" onClick={() => selectOs("macos")} style={toggleButton(!isWindows)}>macOS</button>
        </div>
      </div>

      <div style={{
    marginBottom: "16px"
  }}>
        <label style={labelStyle}>Architecture</label>
        <div style={{
    display: "flex",
    gap: "8px",
    marginTop: "4px"
  }}>
          {archOptions.map(opt => <button key={opt.value} type="button" onClick={() => setArch(opt.value)} style={toggleButton(arch === opt.value)}>
              {opt.label}
            </button>)}
        </div>
      </div>

      <label style={labelStyle}>Install command</label>
      <code style={codeBox}>{command}</code>
      <div style={{
    display: "flex",
    gap: "10px",
    flexWrap: "wrap",
    alignItems: "center"
  }}>
        <button type="button" onClick={() => copy(command, "cmd")} style={copyButton}>
          {copied === "cmd" ? "Copied" : "Copy command"}
        </button>
        <a href={downloadUrl} download style={{
    display: "inline-flex",
    alignItems: "center",
    gap: "7px",
    padding: "7px 16px",
    borderRadius: "8px",
    background: "#F74F4F",
    color: "#fff",
    fontWeight: 600,
    fontSize: "13px",
    textDecoration: "none",
    marginTop: "8px"
  }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <path d="M12 3v12" />
            <path d="M7 11l5 5 5-5" />
            <path d="M5 21h14" />
          </svg>
          Download installer
        </a>
      </div>
      <p style={{
    fontSize: "12px",
    opacity: 0.6,
    marginTop: "6px",
    marginBottom: 0
  }}>{file}</p>

      {isWindows ? <details style={{
    marginTop: "16px"
  }}>
          <summary style={{
    cursor: "pointer",
    fontSize: "14px",
    fontWeight: 600
  }}>Microsoft Intune command-line arguments</summary>
          <p style={{
    fontSize: "13px",
    opacity: 0.7,
    margin: "8px 0"
  }}>
            For an Intune Line-of-business app, upload {file} and paste these into <strong>Command-line arguments</strong>.
          </p>
          <code style={codeBox}>{intuneArgs}</code>
          <button type="button" onClick={() => copy(intuneArgs, "intune")} style={copyButton}>
            {copied === "intune" ? "Copied" : "Copy arguments"}
          </button>
        </details> : <div style={{
    marginTop: "16px"
  }}>
          <div style={innerPanel}>
            <label style={labelStyle}>MDM Deployment</label>
            <p style={{
    ...helpText,
    marginTop: "4px",
    marginBottom: "12px"
  }}>
              The supported fleet path. Download these profiles and assign them with the package.
            </p>
            <div style={{
    display: "flex",
    flexDirection: "column",
    gap: "10px"
  }}>
              {fleetKeySection}
              {quietProfilesSection}
            </div>
          </div>
          <div style={{
    marginTop: "16px"
  }}>
            <label style={labelStyle}>Single machine</label>
            <p style={helpText}>Only if you are not using MDM. After installing, set the key with:</p>
            <code style={{
    ...codeBox,
    marginTop: "8px"
  }}>{setKeyCommand}</code>
            <button type="button" onClick={() => copy(setKeyCommand, "setkey")} style={copyButton}>
              {copied === "setkey" ? "Copied" : "Copy command"}
            </button>
          </div>
        </div>}
    </div>;
};

Velatir for Desktop is a standard MSI (Windows) and PKG (macOS). One ingest key configures every device: no per-feature flags, no per-customer builds.

## Build the installer and profiles

Generate an ingest key on the **Setup** tab of the [Velatir dashboard](https://app.velatir.com). The same key works for every device.

On Windows the key is an installer property. On macOS it lives in **MDM Deployment**: download the ingest-key profile and the two optional quiet-install profiles, then assign them with the package.

<DesktopInstallGenerator />

## Deploy with your MDM

Pick your platform. Each path is: upload the installer, assign the ingest key, assign to devices.

<AccordionGroup>
  <Accordion title="Microsoft Intune (Windows)" icon="microsoft">
    1. **Apps → All apps → Add → Line-of-business app.** Upload the MSI from the builder.
    2. **Command-line arguments:** paste the Intune arguments from the builder.
    3. Assign **Required**. Intune handles elevation.

    To rotate the key, update the arguments and redeploy.
  </Accordion>

  <Accordion title="Jamf Pro (macOS)" icon="apple">
    1. Upload the PKG under **Packages**. Policy: **Recurring Check-in**, **Once per computer**.
    2. Upload the `.mobileconfig` from the builder, scoped to the same Macs. Or **Application & Custom Settings**: domain `com.velatir.agent`, key `ApiKey`. This is the macOS equivalent of the MSI's `INGEST_KEY`.
    3. Upload the **background items** and **notifications** profiles from the builder (or create them in Jamf: Team Identifier `AA7QLU3S4R`, bundle ID `com.velatir.desktopapp`, alert type **Alert**). Assign these first so macOS never shows the background-items prompt.

    Rotate the key by replacing `ApiKey` in the profile — no reinstall.
  </Accordion>

  <Accordion title="Microsoft Intune (macOS)" icon="apple">
    Use **macOS app (PKG)**, not **Line-of-business app**.

    1. **Apps → All apps → Create → macOS → macOS app (PKG).** Upload the PKG from the builder.
    2. **Detection rules:** delete `com.velatir.agent.bootstrap`. Add one entry: bundle ID `com.velatir.desktopapp`, **Ignore app version: Yes**. Confirm one Mac shows **Installed** before you go wide — the wrong rule reinstalls Velatir at every check-in. See [troubleshooting](/desktop-app/troubleshooting#fleet-and-mdm).
    3. **Requirements:** macOS 13.0. Assign **Required**.
    4. **Devices → Configuration → Create → Profile type: Templates → Custom.** Upload the `.mobileconfig` from the builder. Repeat for **background items** and **notifications**. Assign all three to the same groups as the app, and let them arrive first.

    Apple Silicon and Intel are separate packages, assigned to matching device groups. Devices need the Intune management agent (2308.006+) — a profile that applies is not evidence the app can install. Confirm with `velatir status` or the dashboard **Devices** view, not Intune alone.
  </Accordion>

  <Accordion title="SCCM and other tools" icon="server">
    Any tool that runs `msiexec` (Windows) or `installer` (macOS) works: use the command from the builder. For a Windows detection rule, check for the `VelatirAgent` service or the install path `C:\Program Files\Velatir\`.
  </Accordion>
</AccordionGroup>

## Removing Velatir from a fleet

Change the assignment first. While the app is still **Required**, Intune reinstalls it behind the removal.

**Windows.** Set the assignment to **Uninstall**. If devices do not come off, deploy the cleanup script in [Uninstall cleanup](/desktop-app/uninstall-cleanup) as an Intune remediation running as SYSTEM.

**macOS.** The PKG app type has no **Uninstall** assignment, so remove the assignment, then run the bundled uninstaller as a root script under **Devices → Scripts**:

```bash theme={null}
sudo velatir-uninstall
```

If an older version left a system extension on the device, a restart finishes removing it.

## Reference

<AccordionGroup>
  <Accordion title="MSI properties (Windows)" icon="table">
    | Property            | Required    | Description                                                                                                                |
    | ------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
    | `INGEST_KEY`        | Recommended | Stages the ingest key at install time. Hidden from MSI logs. (`VELATIR_API_KEY` is accepted as a deprecated alias.)        |
    | `VELATIR_HIDE_TRAY` | No          | Set to `1` to hide the system-tray icon. Windows only; on macOS use `velatir hide`. `velatir show` reverses it at runtime. |
  </Accordion>

  <Accordion title="Rotate the ingest key" icon="key-round">
    **Windows.** Redeploy with the new key in the command-line arguments.

    **macOS.** Re-download the ingest key profile from the builder and replace the `ApiKey` value in your MDM. Devices apply it on the next check-in, with no reinstall.
  </Accordion>

  <Accordion title="Quiet-install profiles (macOS)" icon="bell">
    Optional. Together they stop the "background items added" alert and turn Velatir's alerts on before anyone sees a prompt. Download them from the builder; assign them to the same Macs as the package, first.

    | Setting                       | Value                                                |
    | ----------------------------- | ---------------------------------------------------- |
    | Team Identifier               | `AA7QLU3S4R`                                         |
    | App bundle ID (notifications) | `com.velatir.desktopapp`                             |
    | Alert type                    | **Alert** (stays on screen), not Banner              |
    | Critical Alerts               | Off unless blocked requests must break through Focus |

    The Managed Login Items payload needs macOS 13+ and an MDM; macOS refuses it in a profile a user installs by hand.

    To mute Velatir's own update and lifecycle toasts, set `ShouldMuteSystemNotifications` to `true` in `com.velatir.agent`. Blocked-request alerts still appear.
  </Accordion>

  <Accordion title="Monitor the fleet" icon="activity">
    Run `velatir status --json` as a Microsoft Intune Remediation or a Jamf Pro extension attribute. It reports client state, version, and the last trace timestamp.
  </Accordion>

  <Accordion title="Pin a version" icon="git-branch">
    Velatir auto-updates by default. To coordinate updates with your own change-management process, contact support to enable a per-tenant update channel.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Permissions" icon="shield-check" href="/desktop-app/permissions">
    What the installer asks for on each platform.
  </Card>

  <Card title="Health checks" icon="heart-pulse" href="/desktop-app/health-checks">
    Monitor agent health across the fleet.
  </Card>

  <Card title="How it works" icon="layers" href="/desktop-app/how-it-works">
    What the desktop client does on each device.
  </Card>

  <Card title="Troubleshooting" icon="life-buoy" href="/desktop-app/troubleshooting">
    Diagnose failures during scaled rollouts.
  </Card>
</CardGroup>
