Build a Vite presentation, zip the dist directory, and upload it to Mobile Locker with a shell script.
Upload a built presentation to Mobile Locker from a shell script.
Before you start
Complete these setup steps before you run the script:
- Get your API token from the admin portal.
- Get the presentation ID from the admin portal.
- Choose the Mobile Locker region where your presentation is stored:
app.mobilelocker.comoreu.mobilelocker.com. - Set
ML_API_TOKENin your environment. - Install the tools the script uses:
npx,vite,zip, andcurl.
Set
ML_API_TOKENandMOBILE_LOCKER_BASE_URLbefore you run the script if you want it to run without prompts, including from CI.
Set your token in the current shell:
export ML_API_TOKEN="your_token_here"Keep your API token secret. Do not commit it to a Git repository or share it with other people.
Optional: Load the token from a local file
If you prefer, save your token in $HOME/.mobilelocker and let the script load it when ML_API_TOKEN is not already set.
echo 'ML_API_TOKEN="your_token_here"' >> "$HOME/.mobilelocker"Upload a presentation
- Save this script to your project root as
deploy-prod.sh.
#!/bin/bash
# Stop on errors, unset variables, and failed piped commands so the script does not continue after a bad state.
set -euo pipefail
# If the token is not already in the environment, try a local fallback file for repeated manual uploads.
if [ -z "${ML_API_TOKEN:-}" ] && [ -f "$HOME/.mobilelocker" ]; then
source "$HOME/.mobilelocker"
fi
# Set values you may need to change for your project or Mobile Locker region.
MOBILE_LOCKER_BASE_URL="${MOBILE_LOCKER_BASE_URL:-}"
PRESENTATION_ID="YOUR_PRESENTATION_ID"
BUILD_DIR="dist"
ZIP_FILE="presentation.zip"
RESPONSE_FILE="$(mktemp)"
# Prompt for the API token only when it was not provided by the environment or local file.
if [ -z "${ML_API_TOKEN:-}" ]; then
read -rsp "Enter your Mobile Locker API token: " ML_API_TOKEN
echo ""
fi
if [ -z "${ML_API_TOKEN:-}" ]; then
echo "Error: ML_API_TOKEN cannot be empty."
exit 1
fi
# Prompt for the Mobile Locker region only when it was not already set.
if [ -z "${MOBILE_LOCKER_BASE_URL:-}" ]; then
while true; do
read -r -p "Enter Mobile Locker base URL (https://app.mobilelocker.com or https://eu.mobilelocker.com): " MOBILE_LOCKER_BASE_URL
# Only accept the two supported regions so uploads do not go to the wrong place.
if [ "$MOBILE_LOCKER_BASE_URL" = "https://app.mobilelocker.com" ] || [ "$MOBILE_LOCKER_BASE_URL" = "https://eu.mobilelocker.com" ]; then
break
fi
echo "Error: Set MOBILE_LOCKER_BASE_URL to https://app.mobilelocker.com or https://eu.mobilelocker.com"
done
fi
# Build the upload endpoint from the region and presentation ID.
API_URL="$MOBILE_LOCKER_BASE_URL/api/presentations/$PRESENTATION_ID/upload"
if [ "$PRESENTATION_ID" = "YOUR_PRESENTATION_ID" ]; then
echo "Error: Replace YOUR_PRESENTATION_ID with your presentation ID."
exit 1
fi
# Validate the region again in case the value came from the environment instead of the prompt.
if [ "$MOBILE_LOCKER_BASE_URL" != "https://app.mobilelocker.com" ] && [ "$MOBILE_LOCKER_BASE_URL" != "https://eu.mobilelocker.com" ]; then
echo "Error: Set MOBILE_LOCKER_BASE_URL to https://app.mobilelocker.com or https://eu.mobilelocker.com"
exit 1
fi
# Vite builds into dist/ by default. Change BUILD_DIR if your output directory is different.
npx vite build
if [ ! -d "$BUILD_DIR" ]; then
echo "Error: Build directory '$BUILD_DIR' was not created."
echo "Check your build output or update BUILD_DIR in this script."
exit 1
fi
# Remove any previous archive so you always upload a fresh build.
rm -f "$ZIP_FILE"
(
cd "$BUILD_DIR"
# Create the archive from the built files so Mobile Locker receives only deployable assets.
zip -r --exclude=.gitignore "../$ZIP_FILE" .
)
# Send the ZIP file to Mobile Locker, save the response body to a temporary file, and capture the HTTP status code separately.
HTTP_STATUS=$(curl --silent --show-error --output "$RESPONSE_FILE" --write-out "%{http_code}" \
--header "Authorization: Bearer $ML_API_TOKEN" \
--form "file=@$ZIP_FILE" \
"$API_URL")
if [ "$HTTP_STATUS" -ge 200 ] && [ "$HTTP_STATUS" -lt 300 ]; then
echo "Upload complete."
echo "You will receive an email when the new version is ready."
else
echo "Upload failed with status $HTTP_STATUS."
# Print the API response so you can see the error returned by Mobile Locker.
cat "$RESPONSE_FILE"
rm -f "$RESPONSE_FILE"
exit 1
fi
# Delete the temporary response file after the request finishes.
rm -f "$RESPONSE_FILE"-
Replace
YOUR_PRESENTATION_IDwith your presentation ID. -
Optional: set
MOBILE_LOCKER_BASE_URLbefore you run the script if you want to skip the region prompt.- Global region:
https://app.mobilelocker.com - European region:
https://eu.mobilelocker.com
- Global region:
-
Make the script executable.
chmod +x deploy-prod.sh- Run the script.
./deploy-prod.shExpected output:
Upload complete.
You will receive an email when the new version is ready.Optional: Customize the script
- If you do not use Vite, replace
npx vite buildwith your build command. - If your build output is not
dist, updateBUILD_DIR. - If
MOBILE_LOCKER_BASE_URLis already set in your shell or CI environment, the script uses that value and does not prompt. - If your presentation is stored in the European region, set
MOBILE_LOCKER_BASE_URLtohttps://eu.mobilelocker.com. - If
ML_API_TOKENis already set in your shell or CI environment, the script uses that value first and does not prompt. - If
ML_API_TOKENis stored in$HOME/.mobilelocker, the script loads that value before prompting. - If you want SMS notifications, add your mobile number to your profile.
Troubleshooting
-
ML_API_TOKEN cannot be empty- Enter your token when prompted, export
ML_API_TOKENin your shell, or add it to$HOME/.mobilelocker.
- Enter your token when prompted, export
-
Replace YOUR_PRESENTATION_ID with your presentation ID- Copy the presentation ID from the admin portal and update
PRESENTATION_IDin the script.
- Copy the presentation ID from the admin portal and update
-
Set MOBILE_LOCKER_BASE_URL to https://app.mobilelocker.com or https://eu.mobilelocker.com- Enter one of the two valid region URLs when prompted, or set
MOBILE_LOCKER_BASE_URLbefore you run the script.
- Enter one of the two valid region URLs when prompted, or set
-
Build directory 'dist' was not created- Confirm that your build completed successfully. If your tool writes files to a different directory, change
BUILD_DIR.
- Confirm that your build completed successfully. If your tool writes files to a different directory, change
-
Upload failed with status ...- Confirm that your API token is valid, the presentation ID is correct, the ZIP file was created before upload, and the script is using the correct Mobile Locker region.
What happens next
Mobile Locker sends you an email when the new version is ready.
You can also refresh the presentations page in the correct admin portal region to check when the upload has finished processing.
- Global region: https://app.mobilelocker.com/admin/presentations
- European region: https://eu.mobilelocker.com/admin/presentations

