Skip to content
Tim edited this page May 24, 2024 · 65 revisions

Some functions require logging in to Scratch. You also need to have the coding language Python installed on your device. Download Python here if you don't have it: https://www.python.org/downloads/

Installation

Run the following command in your command prompt / shell:

pip install -U scratchattach

OR

Add this to your Python code:

import os

os.system("pip install -U scratchattach")

Logging in

Logging in with username / password:

import scratchattach as scratch3

session = scratch3.login("username", "password")

login() returns a Session object that saves your login

Logging in with a sessionId: You can get your session id from your browser's cookies. More information

import scratchattach as scratch3

session = scratch3.Session("sessionId", username="username") #The username field is case sensitive

Attributes:

session.session_id #Returns the associated session id
session.xtoken
session.email #Returns the email address associated with the account
session.new_scratcher #Returns True if the associated account is a New Scratcher
session.mute_status
session.banned #Returns True if the associated account is banned

Cloud variables

Connect to the Scratch cloud:

With a Session object:

conn = session.connect_cloud("project_id")

Directly with a sessionId (cookie connect):

conn = scratch3.CloudConnection(project_id = "project_id", username="username", session_id="sessionId")

Connect to the TurboWarp cloud:

conn = scratch3.connect_tw_cloud("project_id", purpose="(optional) your use case", contact="(optional) your Scratch account or other contact info")
# Optional arguments: purpose and contact
# Providing these arguments allows TurboWarp to understand what you're using their cloud server for.
# Warning: TurboWarp may block bots that cause excessive cloud traffic without providing their purpose

Alternative ways to do connect to the TurboWarp cloud:

conn = session.connect_tw_cloud("project_id")
conn = scratch3.TwCloudConnection(project_id = "project_id", username="username", cloud_host="wss://clouddata.turbowarp.org")  
# Optional argument: cloud_host (for connecting to custom websockets)
# To connect to forkphorus's cloud server, use cloud_host="wss://stratus.turbowarp.org"

Set a cloud var:

conn.set_var("variable", "value") #the variable name is specified without the cloud emoji

Get a cloud var:

Get Scratch cloud variables:

value = scratch3.get_var("project_id", "variable")
variables = scratch3.get_cloud("project_id") #Returns a dict with all cloud var values
logs = scratch3.get_cloud_logs("project_id") #Returns the cloud logs as list

Get TurboWarp cloud variables: Do not spam these methods, they create a new cloud connection everytime they are called

value = scratch3.get_tw_var("project_id", "variable", purpose="your use case (optional)", contact="your Scratch account or other contact info (optional)")
variables = scratch3.get_tw_cloud("project_id", purpose="your use case (optional)", contact="your Scratch account or other contact info (optional)")

Close the cloud connection:

conn.disconnect()

Encoding / Decoding

Scratchattach has a built in encoder. Scratch sprite to decode texts encoded with scratchattach (click the link to download it): https://github.com/TimMcCool/scratchattach/raw/main/assets/Encoder.sprite3

from scratchattach import Encoding

Encoding.encode("input") #will return the encoded text
Encoding.decode("encoded") #will decode an encoded text

scratch3.encoder.letters #returns the list with letters used by the encoder. You can set indices of this list to add / remove letters. The indices of the letters in this list correspond to the indices of costumes in the Scratch sprite
Encoding.replace_char("old_char", "new_char") #replaces a character in the above list. Don't forget to replace the character in the customes of the Scratch sprite too.

Cloud events

Cloud events allow reacting to cloud events in real time. If a Scratcher sets / creates / deletes a cloud var on the given project, an event will be called.

They do not require a session because they use the clouddata logs to receive cloud updates.

How to use with Scratch:

import scratchattach as scratch3

events = scratch3.CloudEvents("project_id")

@events.event
def on_set(event): #Called when a cloud var is set
    print(f"{event.user} set the variable {event.var} to the value {event.value} at {event.timestamp}")

@events.event
def on_del(event):
    print(f"{event.user} deleted variable {event.var}")

@events.event
def on_create(event):
    print(f"{event.user} created variable {event.var}")

@events.event #Called when the event listener is ready
def on_ready():
   print("Event listener ready!")

events.start()

How to use with TurboWarp:

import scratchattach as scratch3

events = scratch3.TwCloudEvents("project_id", purpose="your use case (optional)", contact="your Scratch account or other contact info (optional)")

...

Cloud events that use a scratch3.CloudConnection object to receive cloud updates:

import scratchattach as scratch3

session = scratch3.Session("session_id", username="username") #Replace with your data
conn = session.connect_cloud("project_id")
events = scratch3.WsCloudEvents("project_id", conn)

...

Functions:

events.start(thread=True)
events.pause()
events.resume()
events.stop()

Cloud Requests

Cloud Requests Framework (inspired by discord.py) that allows Scratch projects and Python to interact

This makes it possible to access data like message counts, user stats and more from Scratch projects! Uses cloud variables to transmit data.

Cloud Requests are documented on this page:

https://github.com/TimMcCool/scratchattach/blob/main/CLOUD_REQUESTS.md

If you want to access external information in Scratch projects or store data on an external database, scratchattach's Cloud Requests are ideal for your project:

  • Similar to cloud events, but send back data to the project
  • Automatically encode / decode sent data
  • Tons of extra features

Users

Get a user:

user = session.connect_user("username")

Get the user that you are logged in with:

session.get_linked_user()

You can also get users without logging in: (but then you can't use any methods that require a login, like user.follow(), user.post_comment(), ...)

user = scratch3.get_user("username") # Warning: Any methods that require authentication will not work on the returned object

Attributes:

user.join_date
user.about_me
user.wiwo #Returns the user's 'What I'm working on' section
user.country #Returns the country from the user profile
user.icon_url #Returns the link to the user's pfp (90x90)
user.id #Returns the id of the user
user.scratchteam #Retuns True if the user is in the Scratch team
# ----- ----- #
user.update() #Updates the above data

Functions:

user.message_count()
user.featured_data() #Returns info on the user's featured project as dict
user.does_exist() #Returns True if the user exists and False if the user is deleted. New in v1.7.3
user.is_new_scratcher() #Returns whether the user is a new Scratcher. New in v1.7.3

user.follower_count()
user.following_count()
user.project_count()
user.favorites_count() #Returns the amount of projects the user has favorited
user.studio_count() #Returns the amount of studios the user is curating
user.studio_following_count()

user.follower_names(limit=40, offset=0) #Returns the followers as list of usernames (strings). New in v1.1.5
user.following_names(limit=40, offset=0) #Returns the people the user is following as a list of usernames (strings). New in v1.1.5

user.followers(limit=40, offset=0) #Returns the followers as list of scratch3.User objects
user.following(limit=40, offset=0) #Returns the people the user is following as list of scratch3.User objects
user.projects(limit=None, offset=0) #Returns the projects the user has shared as list of scratch3.Project objects
user.favorites(limit=None, offset=0) #Returns the projects the user has favorited as list of scratch3.Project objects
user.studios(limit=None, offset=0) #Returns the studios the user is curating as list of dicts

user.viewed_projects(limit=24, offset=0) #To use this you need to be logged in as the user. Returns the projects the user has recently viewed as list of scratch3.Project objects
user.activity(limit=1000) # Returns the user's activity as parsed list of dicts
user.activity_html(limit=1000) #Returns the user's activity as raw HTML document

user.follow()
user.unfollow()
user.is_following("scratcher") #Returns True if user is following the specified Scratcher
user.is_followed_by("scratcher") #Returns True if user is followed by the specified Scratcher

user.comments(limit=20, page=1) #Returns the user's profile comments
user.post_comment("comment content") #Posts a comment on the user's profile. Requires logging in. Returns the info of the posted commented.
user.reply_comment("comment content", parent_id="parent_id", commentee_id="commentee_id") #Replies to a specified profile comment. Requires logging in. Returns the info of the posted commented.
user.delete_comment(comment_id="comment_id")
user.report_comment(comment_id="comment_id")

user.toggle_commenting()
user.set_bio(text) #Changes the 'About me' of the user
user.set_wiwo(text)
user.set_featured("project_id", label="") #Changes the featured project
user.set_forum_signature(text) # Changes the discuess forum signature of the user. New in v1.7.3

user.stats() #Returns the user's statistics as dict. Fetched from ScratchDB
user.ranks() #Returns the user's ranks as dict. Fetched from ScratchDB
user.followers_over_time(segment=1, range=30) #Fetched from ScratchDB

user.forum_posts(page=0, order="newest") #Returns a list of scratch3.ForumPost objects. New in v0.5.5. Fetched from ScratchDB
user.forum_counts() #Returns the amount of posts a user has written different forums as dict. Fetched from ScratchDB
user.forum_counts_over_time() #Fetched from ScratchDB
user.forum_signature() #Fetched from ScratchDB
user.forum_signature_history() #A change log for the user's forum history. Fetched from ScratchDB

user.ocular_status() #Returns information about the user's ocular status, like the status text, the color, and the time of the last update.

Projects

Get a project:

project = session.connect_project("project_id")

You can also get projects without logging in: (but then you can't use any functions that require a login, and you can't get your unshared projects)

project = scratch3.get_project("project_id") # Warning: Any methods that require authentication will not work on the returned object

Attributes:

project.id  #Returns the project id
project.url  #Returns the project url
project.title #Returns the project title
project.author  #Returns the username of the author
project.comments_allowed  #Returns True if comments are enabled
project.instructions
project.notes  #Returns the 'Notes and Credits' section
project.created  #Returns the date of the project creation
project.last_modified  #Returns the date when the project was modified the last time
project.share_date
project.thumbnail_url
project.remix_parent
project.remix_root
project.loves  #Returns the love count
project.favorites #Returns the project's favorite count
project.remix_count  #Returns the number of remixes
project.views  #Returns the view count
project.project_token
# ----- ----- #
project.update()  #Updates the above data

Functions:

project.get_author()  #Returns the author as scratch3.User object
project.ranks()  #Returns the project's ranks. Fetched from ScratchDB
project.moderation_status() #Returns the project's moderation status (either "safe" or "notsafe" (nfe)). New in v0.5.4. Fetched from jeffalo.net

project.comments(limit=40, offset=0)  #Fetches all project comments except for comment replies
project.get_comment(comment_id="comment_id") #Gets a specific comment by its ID and returns it as a dict
project.get_comment_replies(comment_id="comment_id", limit=40, offset=0)  #Fetches the replies to a specific comment
project.post_comment(content="comment content")  #Returns the info of the posted commented.
project.reply_comment(content="comment content", parent_id="parent_id", commentee_id="commentee_id")  #Returns the info of the posted commented.
project.delete_comment(comment_id="comment_id")
project.report_comment(comment_id="comment_id")

project.love()
project.unlove()
project.favorite()
project.unfavorite()
project.post_view()

project.set_title("new title")
project.set_instructions("new instructions")
project.set_notes("new notes and credits")  #Sets the notes and credits section of the project
project.set_thumbnail(file="filename.png") #File must be .png and fit Scratch's thumbnail guidelines
project.set_json(json_data) #Sets the project JSON. Can be used to upload projects. json_data must be a dict or an encoded JSON object with the project JSON.
project.share()
project.unshare()
project.is_shared() #Returns True if the project is currently shared

project.turn_off_commenting()
project.turn_on_commenting()
project.toggle_commenting()

project.remixes(limit=None, offset=0) #Returns the remixes as list of scratch3.Project
project.studios(limit=None, offset=0) #Returns the studios the project is in as list of dicts

project.download(filename="project_name.sb3", dir="") #Downloads the project to your computer. The downloaded file will only work in the online editor
project.get_raw_json() #Returns the JSON of the project content as dict
project.get_creator_agent() #Returns the user-agent of the user who created the project (with information about their browser and OS)
project.upload_json_from("project_id") #Uploads the project json from the project with the given to the project represented by this Project object. New in v1.6.2

Unshared projects

When connecting / getting a project that you can't access, a PartialProject object is returned instead.

Most attributes and most functions don't work for such projects. However, these still work:

project.remixes(limit=None, offset=0)
project.is_shared() # Will always return False for PartialProject objects

Studios

Get a studio:

studio = session.connect_studio("studio_id")

You can also get studios without logging in: (But then you can't use any functions that require a login, like studio.follow(), studio.add_project(), ...)

studio = scratch3.get_studio("studio_id") # Warning: Any methods that require authentication will not work on the returned object

Attributes:

studio.id
studio.title
studio.description
studio.host_id #The user id of the studio host
studio.open_to_all #Whether everyone is allowed to add projects
studio.comments_allowed
studio.image_url
studio.created
studio.modified
studio.follower_count
studio.manager_count
studio.project_count
# ----- ----- #
studio.update()  #Updates the above data

Functions:

studio.follow()
studio.unfollow()

studio.comments(limit=40, offset=0)  #Fetches all project comments except for comment replies
studio.get_comment(comment_id="comment_id") #Gets a specific comment by its ID and returns it as a dict
studio.get_comment_replies(comment_id="comment_id", limit=40, offset=0)  #Fetches the replies to a specific comment
studio.post_comment(content="comment content")  #Returns the info of the posted commented.
studio.reply_comment(content="comment content", parent_id="parent_id", commentee_id="commentee_id")  #Returns the info of the posted commented.

studio.add_project("project_id")
studio.remove_project("project_id")

studio.set_description("new description")
studio.set_title("new title")
studio.set_thumbnail(file="filename.png") # New in v1.4.5. File must fit Scratch's thumbnail guidelines. Returns a link to the uploaded thumbnail.
studio.open_projects() #Allows everyone to add projects
studio.close_projects()

studio.turn_off_commenting() # New in v1.0.1
studio.turn_on_commenting()
studio.toggle_commenting()

studio.invite_curator("username")
studio.promote_curator("username")
studio.remove_curator("username")
studio.accept_invite() #If there is a pending invite for you, this function will accept it
studio.leave() #Removes yourself from the studio

studio.projects(limit=40, offset=0)
studio.curators(limit=24, offset=0) #Returns the curators as list of users (scratch3.User)
studio.managers(limit=24, offset=0)
studio.activity(limit=24, offset=0) #New in v1.0.1

Search / Explore page

Doesn't require a session

Search:

session.search_projects(query="query", mode="trending", language="en", limit=40, offset=0)
scratch3.search_projects(query="query", mode="trending", language="en", limit=40, offset=0) #Doesn't require logging in

scratch3.search_studios(query="query", mode="trending", language="en", limit=40, offset=0)

session.search_posts(query="query", order="newest", page=0) #Searches forum posts. Returns a list of scratch3.ForumPost objects
scratch3.search_posts(query="query", order="newest", page=0) #Doesn't require logging in

Get the explore page:

session.explore_projects(query="*", mode="trending", language="en", limit=40, offset=0)
scratch3.explore_projects(query="*", mode="trending", language="en", limit=40, offset=0) #Doesn't require logging in

scratch3.explore_studios(query="*", mode="trending", language="en", limit=40, offset=0)

Messages / My stuff page

session.mystuff_projects("all", page=1, sort_by="") #Returns the projects from your "My stuff" page as list

session.messages(limit=40, offset=0) #Returns your messages as dict
session.clear_messages() #Marks your messages as read
session.get_message_count() #Returns your message count

Frontpage

scratch3.get_news(limit=10, offset=0) #Returns the news from the Scratch front page as list

scratch3.featured_projects() #Returns the featured projects from the Scratch homepage as list
scratch3.featured_studios()
scratch3.top_loved()
scratch3.top_remixed()
scratch3.newest_projects() #Returns a list with the newest Scratch projects. This list is not present on the Scratch home page, but the API still provides it.
scratch3.design_studio_projects()
scratch3.curated_projects()

session.get_feed(limit=20, offset=0) #Returns your "What's happening" section from the Scratch front page as list
session.loved_by_followed_users(limit=40, offset=0) #Returns the projects loved by users you are following as list

Forum topics

All of this data is fetched from ScratchDB v3, therefore it may be slighty off.

Get a forum topic:

topic = session.connect_topic("topic_id")

You can also get topics without logging in:

topic = scratch3.get_topic("topic_id") # Warning: Any methods that require authentication will not work on the returned object

Get a list of the topics in a category:

topic_list = session.connect_topic_list("category_name", page=0)

You can also do this without logging in:

topic_list = scratch3.get_topic_list("category_name", page=0) # Warning: Any methods that require authentication will not work on the returned objects

Attributes:

topic.title
topic.category
topic.closed
topic.deleted
topic.post_count
# ----- ----- #
topic.update()  #Updates the above data

Functions:

topic.posts(page=0, order="oldest") #Returns the topic posts as list of scratch3.ForumPost objects. Possible parameters for "order" are "oldest" and "newest"
topic.first_post() #Returns the first topic post as scratch3.ForumPost object
topic.follow()
topic.unfollow()

topic.post_count_by_user("username")
topic.activity() #Returns an activity / change log for the topic

To prevent spam, adding posts to topics is not a scratchattach feature and never will be.

Forum posts

All of this data is fetched from ScratchDB v3, therefore it may be slighty off.

Get a forum post:

post = session.connect_post("post_id")

You can also get posts without logging in:

post = scratch3.get_post("post_id")  # Warning: Any methods that require authentication will not work on the returned object

Search for forum posts:

post_list = session.search_posts(query="query", order="newest", page=0) #Returns a list of scratch3.ForumPost objects

You can also get posts without logging in:

post_list = scratch3.search_posts(query="query", order="newest", page=0) #Returns a list of scratch3.ForumPost objects

Attributes:

post.id
post.author
post.posted #The date the post was made
post.edited #The date of the most recent post edit. If the post wasn't edited this is None
post.edited_by #The user who made the most recent edit. If the post wasn't edited this is None
post.deleted #Whether the post was deleted
post.html_content #Returns the content as HTML
post.bb_content #Returns the content as BBCode
post.topic_id #The id of the topic the post is in
post.topic_name #The name of the topic the post is in
post.topic_category #The name of the category the post topic is in
# ----- ----- #
post.update()  #Updates the above data

Functions:

post.get_topic() #Returns the topic the post is in as scratch3.ForumTopic object
post.get_author() #Returns the post author as scratch3.User object

post.edit(new_content) #Requires you to be the post author.

post.ocular_reactions()

Site stats and health

scratch3.total_site_stats() #Returns the total project count, user count, comment count and other total counts
scratch3.monthly_site_traffic() #Returns last month's site traffic
scratch3.country_counts() #Returns the amount of Scratch users in each country
scratch3.age_distribution() #Returns how many Scratchers were 1,2,3,4,5,6,... years old when they created their account

scratch3.get_health() #Returns Scratch's health data

Backpack

session.backpack(limit=20, offset=0) #Returns the contents of your backpack as dictionary
session.delete_from_backpack("asset id") #Deletes an asset from your backpack