Skip to main content

🚀 LocketLam - The Ultimate Python SDK for Locket Camera

LocketLam Banner

A production-ready, feature-complete Python client library for Locket Camera with authentic iOS hardware simulation.

PyPI Version Python Versions License MIT Downloads Vietnamese Docs


🗃️ Documentation Map

You are here: README — the front page. Read this to understand what the library does and whether it suits your needs.

If you want to... Go to
🚀 Install & run your first snippet You're in the right place — see Quick Start below
🛠️ Integrate into your project step by step ➡️ INTEGRATION.md (EN) · INTEGRATION_VI.md (VI)
📚 Look up a specific method / parameter ➡️ FEATURES.md (EN) · FEATURES_VI.md (VI)
💡 Copy-paste complete working scripts ➡️ examples/en/ (EN) · examples/vi/ (VI)
🇬🇧 Read this page in Vietnamese ➡️ README_VI.md

📖 Table of Contents


🌟 Overview

locketlam is a reverse-engineered Python SDK designed to provide direct programmatic access to the Locket Camera backend. It allows developers, bot creators, and automation engineers to interact seamlessly with Locket accounts using pure Python, without needing an iOS device running.


✨ Key Features

  • 📱 100% Authentic iOS Hardware Emulation: Sends real iPhone hardware identifiers (iPhone 13 Pro through iPhone 15 Pro Max), bundle IDs (com.locket.Locket), Firebase GMPIDs, and Google Protobuf analytics flags to ensure requests are never blocked or flagged.
  • 🔄 Autonomous Token Renewal: Automatic background Firebase JWT idToken refreshing whenever a token is near expiry.
  • 🖼️ Smart Media Pipeline: Built-in Pillow conversion automatically transforms .jpg, .png, and other standard formats into Locket-optimized .webp format, uploaded via Google Cloud Storage Resumable protocol.
  • ⚡ Real-Time WebSocket Support: Asynchronous live event listener for direct chat messages via wss://api.locketcamera.com/wss_v2/chat.
  • 🛡️ Defensive Architecture: Strongly-typed exceptions (AuthenticationError, StorageUploadError, LocketAPIError) for robust error handling.

📦 Installation

Install the library directly from PyPI:

pip install locketlam

Or install with development dependencies:

pip install locketlam[dev]

To install from source in editable mode:

git clone https://github.com/leanhminh2104/locketlam.git
cd locketlam
pip install -e .

⚡ Quick Start

from locketlam import LocketClient

# 1. Initialize client (auto-loads locketlam_session.json if available)
client = LocketClient(session_path="locketlam_session.json")

# 2. Authenticate if first time
if not client.is_authenticated():
    client.login("your_email@gmail.com", "your_password")
    print("Logged in successfully! User UID:", client.session.uid)

# 3. Fetch profile
profile = client.user.get_profile()
print(f"Welcome, {profile.get('first_name')} {profile.get('last_name')} (@{profile.get('username')})")

# 4. Post a moment photo
moment = client.moments.post(
    image="daily_snapshot.jpg",
    caption="Captured with locketlam! ✨",
    is_private=False
)
print("Moment posted successfully! ID:", moment.get("canonical_uid"))

📚 Comprehensive API Reference

1. Authentication & Session Management

The SessionManager handles credentials, refresh tokens, and JWT tokens securely.

from locketlam import LocketClient

client = LocketClient(session_path="session.json")

# Login with email and password
session_data = client.login("email@example.com", "password")

# Check authentication state
if client.is_authenticated():
    print("User UID:", client.session.uid)
    print("Access Token:", client.session.id_token[:20] + "...")

# Force manual token refresh
client.session.refresh()

2. User Profile Management

Access via client.user:

# 1. Get profile (self or another user by UID)
my_profile = client.user.get_profile()
other_profile = client.user.get_profile(user_uid="TARGET_USER_UID")

# 2. Update display name
client.user.update_name(first_name="Lam", last_name="Dev")

# 3. Update birthdate (format: YYYY-MM-DD)
client.user.update_birthdate("2006-04-21")

# 4. Update avatar picture
client.user.update_avatar("https://firebasestorage.googleapis.com/...")

# 5. Sync client data (push notifications, app version)
client.user.sync_client_data(push_notifications=True)

3. Moments (Feed & Uploads)

Access via client.moments:

from locketlam import NoteType

# 1. Post a photo moment with rich gradient badge pill (Supports 158+ presets!)
photo_moment = client.moments.post(
    image="photo.jpg",                          # File path, bytes, or Storage URL
    note_type=NoteType.FLEX_DEN_HOI_THO_CUOI,  # Preset pill badge (custom gradient)
    is_private=False,                          # True = sent only to self (sent_to_self_only)
    recipients=None                            # Specific friends (or None for all)
)

# 2. Post with custom caption, custom gradient colors and custom emoji
custom_moment = client.moments.post(
    image="photo.jpg",
    caption="Coding with AI",
    icon="⚡",
    colors=["#FF416C", "#8A2387"],
    is_private=False
)

# 3. Post a video moment (Supports auto-compression HEVC < 6 MB, 15s to 5-10 mins)
video_moment = client.moments.post(
    image="thumb.jpg",                          # Video thumbnail image
    video="clip_10s.mp4",                       # Video file path, bytes, or Storage URL
    note_type=NoteType.MUSIC                    # Dynamic music overlay
)

# 4. Retrieve actual shared moments by Username (e.g. latest moments of a friend)
friend_moments = client.moments.get_posts_by_username("friend_username", limit=10)
for m in friend_moments:
    print(m["moment_uid"], m["thumbnail_url"], m["caption"])

# 5. React to a friend's moment with emoji
client.moments.react(moment_uid="MOMENT_ID", reaction="❤️")

# 6. Fetch moment view count and viewer list
views = client.moments.get_views(moment_uid="MOMENT_ID")
print("Views count:", views.get("count"))
print("Viewers:", views.get("moment_views"))

# 7. Comment on a moment (attaches to moment and appears in direct chat)
client.moments.comment(
    moment_uid="MOMENT_ID",
    receiver_uid="FRIEND_UID",
    text="Great shot!"
)

# 7. Mark moment as viewed
client.moments.mark_as_viewed(moment_uid="MOMENT_ID")

# 8. Fetch weekly Rollcall event posts
rollcall = client.moments.get_rollcall_posts()
print("Rollcall posts:", rollcall.get("posts", []))

# 9. Fetch latest feed from friends
feed = client.moments.get_latest()
for post in feed:
    print(post.get("user"), post.get("caption"), post.get("thumbnail_url"))

# 10. Delete a moment
client.moments.delete(moment_uid="MOMENT_CANONICAL_UID")

4. Friends, Groups & Blocking

Access via client.friends:

# 1. Retrieve all friends with full profile details (UID, Names, Username, Avatar)
friends = client.friends.get_all_friends()
for f in friends:
    print(f"Friend: {f.get('first_name')} (@{f.get('username')}) - UID: {f.get('uid')}")

# 2. Retrieve groups state
groups_state = client.friends.get_groups_and_friends()

# 3. Resolve invite token from public profile link (https://locket.cam/<username>)
token = client.friends.resolve_invite_token_from_username("friend_username")
print("Invite Token:", token)

# 4. Fetch user details from invite token
user_info = client.friends.fetch_user_by_invite_token(token)
print("User info:", user_info)

# 5. Send friend request by username or UID
client.friends.send_request_by_username("friend_username")
# Or: client.friends.send_request(user_uid="TARGET_USER_UID")

# 6. Accept incoming friend request
client.friends.accept_request(user_uid="TARGET_USER_UID")

# 7. Remove (unfriend), Block & Unblock
client.friends.remove(user_uid="TARGET_USER_UID")
client.friends.block(user_uid="TARGET_USER_UID")   # Blocks user & automatically unfriends them on Locket
client.friends.unblock(user_uid="TARGET_USER_UID") # Unblocks user (removes from blocked_users)

5. Chat & Real-Time WebSockets

Access via client.chat:

# 1. Send direct message or emoji
client.chat.send_message(
    receiver_uid="FRIEND_UID",
    text="Hey, check out this moment! ❤️"
)

# 2. Share a moment into chat (standalone or with text)
# a) Send standalone moment:
client.chat.send_moment(
    receiver_uid="FRIEND_UID",
    moment_uid="MOMENT_UID"  # Your moment UID or a friend's moment UID
)

# b) Send moment with accompanying text message:
client.chat.send_moment(
    receiver_uid="FRIEND_UID",
    moment_uid="MOMENT_UID",
    text="Check out this awesome moment!"
)

# 3. Get inbox conversations list
conversations = client.chat.get_conversations()

# 4. Retrieve live chronological messages from server
messages = client.chat.get_messages(other_user_id="FRIEND_UID")

# 4. React with single or multi-emoji combo to a message
client.chat.send_reaction(conversation_id="CONV_ID", message_id="MSG_ID", emoji="❤️")
client.chat.send_reaction(conversation_id="CONV_ID", message_id="MSG_ID", emoji="🔥🥰")

# 5. Remove / unreact an emoji reaction
client.chat.remove_reaction(conversation_id="CONV_ID", message_id="MSG_ID")

# 6. Recall / unsend your own message
client.chat.delete_message(conversation_uid="CONV_ID", message_uid="MSG_ID")

# 7. Mark conversation as read (send_read_receipt=False for Ghost / Incognito mode)
client.chat.mark_as_read(conversation_uid="CONV_ID", send_read_receipt=True)
client.chat.mark_as_read(conversation_uid="CONV_ID", send_read_receipt=False)

# 8. Listen to live incoming messages over WebSocket
import asyncio

async def on_new_message(msg):
    print("New incoming message:", msg)

# Start event loop
asyncio.run(client.chat.listen_realtime("FRIEND_UID", on_new_message))

6. Device Profile Customization

By default, locketlam picks a realistic iPhone profile. You can also specify custom hardware attributes:

from locketlam import LocketClient, DeviceProfile

custom_device = DeviceProfile(
    model_info={
        "model": "iPhone16,1",
        "name": "iPhone 15 Pro",
        "hw": "hw/iPhone16_1",
        "ios": "18.1.0"
    },
    app_version="2.68.0",
    build_number="2523"
)

client = LocketClient(session_path="session.json", device=custom_device)
print("Emulating:", client.device.user_agent)

7. Error Handling

All custom exceptions inherit from LocketError:

from locketlam.exceptions import (
    LocketError,
    AuthenticationError,
    LocketAPIError,
    StorageUploadError
)

try:
    client.login("user@email.com", "wrong_password")
except AuthenticationError as e:
    print("Auth Failed:", e)
except StorageUploadError as e:
    print("Media Upload Failed:", e)
except LocketAPIError as e:
    print(f"API Error (Status {e.status_code}):", e)
except LocketError as e:
    print("General Locket Error:", e)

💡 Examples

The examples/ directory contains complete, runnable scripts for every feature:

Feature Script
Login & Session examples/en/01_login_and_session.py
User Profile examples/en/02_user_profile.py
Post Photo & NoteType examples/en/03_post_image_moment.py
Post Video & HEVC examples/en/04_post_video_moment.py
Feed & Reactions examples/en/05_feed_views_reactions.py
Friends & Contacts examples/en/06_friends_and_contacts.py
Chat & Real-Time examples/en/07_chat_and_reactions.py
Interactive CLI examples/en/interactive_demo.py
python examples/en/interactive_demo.py

📖 For a full step-by-step integration guide, see docs/INTEGRATION.md. 📋 For the complete API catalog, see docs/FEATURES.md.


📚 Next Steps

Document Description
📘 docs/INTEGRATION.md Step-by-step integration guide with real code snippets for every feature (EN - Primary)
📘 docs/INTEGRATION_VI.md Step-by-step integration guide in Vietnamese (VI - Secondary)
📋 docs/FEATURES.md Full API catalog — all classes, methods and parameters (EN)
📋 docs/FEATURES_VI.md Full API catalog in Vietnamese (VI)
💡 examples/en/ 8 complete runnable example scripts (English)
💡 examples/vi/ 8 complete runnable example scripts (Vietnamese)

🤝 Contributing

Contributions, bug reports, and feature requests are welcome!

  1. Fork the Project.
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature).
  3. Commit your Changes (git commit -m 'Add some AmazingFeature').
  4. Push to the Branch (git push origin feature/AmazingFeature).
  5. Open a Pull Request.

💖 Support & Donations (Sponsor)

If you find locketlam helpful in your projects, automations, or research, please consider supporting the development. Your contribution helps maintain the library, reverse-engineer future Locket updates, and keep the project active!

Gateway / Method Payment Details
🌐 Official Donation Portal https://leanhminh.io.vn/donate
🏦 MB Bank (Vietnam Banking) Account Number: 2104200637
Account Holder: LE VAN ANH MINH
🏦 ACB Bank (Asia Commercial Bank) Account Number: 22002921
Account Holder: LE VAN ANH MINH
🟡 Binance (UID / Pay ID) 283319011
💳 PayPal (Global) paypal.me/leanhminh2104

Every contribution, no matter how small, is deeply appreciated. Thank you very much! ❤️


Copyright © 2026 LAMDev x DaLyMMO.com.

Distributed under the MIT License. See LICENSE for more information.


⚠️ Disclaimer

This library is an unofficial, reverse-engineered project created for educational and developer interoperability purposes. It is not endorsed by, associated with, or affiliated with Locket Camera, Inc. Please use this tool responsibly and respect Locket Camera's terms of service and community guidelines.

Metadata

Release files for locketnoni 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for locketnoni 1.0.2
File Size Uploaded
locketnoni-1.0.2.tar.gz 56.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for locketnoni 1.0.2
File Interpreter ABI Platform
locketnoni-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 108.6 kB

Release files / locketnoni-1.0.2.tar.gz

Download URL locketnoni-1.0.2.tar.gz
Size 56.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c93610980213b41c3ca0d41821924c102a23b5d978141def89b5297b93b3e1b7
BLAKE2b-256 checksum
How to use checksums
4d5fe74e028794540cae7c4e9a7b7fcf416da9a8ed731760977764ee92e6c60a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / locketnoni-1.0.2-py3-none-any.whl

Download URL locketnoni-1.0.2-py3-none-any.whl
Size 52.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67f087d01af9a52b311e32dc6203da5751aeb8f5cd9231d936ea655f38722a1d
BLAKE2b-256 checksum
How to use checksums
9801c64fd93a69476922c2e273dbe283a6ebebfaf6e7a3cd32670b2ff6f7e336
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page