Projects, of course, comprise the bulk of Scratch. These endpoints provide the up-to-date ways of interacting with projects, as used by the migrated project page.
There are two components that make up the identity of a project: its data, which is the actual project file, and its details, which is information like who made it, its notes and credits, and its current love-it/favorite counts. Of course you'll want the first if you're working with the actual programs represented by projects. Unlike most parts of the Scratch API, you don't actually use https://api.scratch.mit.edu to download projects - instead you use a separate domain, https://projects.scratch.mit.edu:
> GET https://projects.scratch.mit.edu/276660597
< {"targets":[{"isStage":true,"name":"Stage", ...
As shown in the example above, using this endpoint yields the project.json
file that represents the project - not the actual .sb2
or .sb3
that you would download from inside the Scratch editor. (The exception to that rule is Scratch 1.4 projects, which do return the entire project binary.) While that file may be enough for your own use case, if you want to fetch the costumes and sounds used in the project, you'll need to make additional requests, this time to https://assets.scratch.mit.edu:
> GET https://assets.scratch.mit.edu/318125267295c8b3ec257bf7f81c6fd3.svg
< <svg xmlns="http://www.w3.org/2000/svg" ...
The ID you use there is included in the project.json
fetched from projects.scratch.mit.edu. Exactly how that value is specified depends on whether the project you're analyzing was made in Scratch 3.0 or 2.0:
- Scratch 3.0: Look for the
md5ext
property on asset objects. This is also equal to{assetId}.{dataFormat}
. - Scratch 2.0: It depends on whether the asset is a sound or a costume:
- Sounds: Use the
md5
property. - Costumes (and backdrops): Most of the time you can use the
baseLayerMD5
property, but if the costume was converted from opening a Scratch 1.4 project in 2.0, it might also include atextLayerMD5
property. If so, you'll get the most accurate image by fetching both of those assets and overlaying the image oftextLayerMD5
on top of that ofbaseLayerMD5
.
- Sounds: Use the
Since Scratch 1.4 projects are served as the full binary, including any costumes and sounds, you'll never have to fetch their assets individually. (You wouldn't be able to, anyway, since they aren't individually stored on the Scratch servers.)
Now if you just want the project's details, there's an ordinary API endpoint for that:
> https://api.scratch.mit.edu/projects/276660597
< {"id":"276660597",""title":"3.0h My Floss!" ...
The /projects/<id>
endpoint returns a project object, which takes the following form:
{
id: 276660597,
title: "3.0h My Floss!",
description: "Thanks to @champ99 and @mres for joining me..."
instructions: "Ahhhh! A new year is here and so is Scratch 3.0 :D..."
visibility: "visible"
public: true
comments_allowed: false
is_published: true
author: {...}
image: "https://cdn2.scratch.mit.edu/get_image/project/276660597_480x360.png"
images: {
282x218: "https://cdn2.scratch.mit.edu/get_image/project/276660597_282x218.png?v=1546617266"
216x163: ...
...
}
history: {
created: "2019-01-02T18:38:37.000Z"
modified: "2019-01-04T15:54:26.000Z"
shared: "2019-01-02T19:55:46.000Z"
}
stats: {
views: 15510
loves: 1109
favorites: 737
comments: 1177
remixes: 123
}
remix: {
parent: 276664853
root: 276660597
}
}
(Well, those values in remix
aren't actually for "3.0h My Floss!". They're for a different project, 3.0h My Floss! remix remix. :))
Most of those properties are self-descriptive, but not all, so here's a quick overview of some of the less obvious options:
author
: This is the author of the project, and it's (almost) a whole user object. See the page Working with Users. The only properties that are missing areprofile.id
,profile.bio
, andprofile.country
.description
: This is the text contents in "Notes and Credits";instructions
is the text in "Instructions".image
,images
: These are full URLs to the thumbnails for the project.image
refers to the highest-resolution file; the options inimages
are all smaller versions of the same image.remix
: Theparent
property is the ID of the project that this project was remixed off of;root
is the original project in the "remix tree". If this project is a remix of that first project,parent
androot
will have the same value.is_published
: This boolean tells if the author of the project has shared it or not.public
: This property is more complex but basically is a combination ofis_published
and moderation checks, like whether the project's been censored or if the author's account has been deleted.visibility
: This is sort of a boolean telling if the project is in the trash section of the author's "My Stuff" page; it takes the values"visible"
and"notvisible"
, though, nottrue
andfalse
.
There's also an endpoint specifically for getting information about whether a project is "censored" or not - /users/<author>/projects/<id>/visibility
:
> GET https://api.scratch.mit.edu/users/_nix/projects/200903024/visibility?x-token=...
< {"projectId":277771344,"deleted":false,...
Do note that the request requires authorization!
That object takes the following form:
{
projectId: 277771344
deleted: false
censored: false
reshareable: true
message: ""
}
A project being censor
ed means that it's been totally hidden from the community, usually as the result of a Scratch Team member responding to the project being reported. The message
property includes the text they wrote, which may include telling you to make changes before re-sharing the project - whether you can do that is specified by the reshareable
property.
The deleted
property doesn't have to do with censorship; it just means whether or not the project is in the trash section of the author's "My Stuff".
Uploading a project means submitting its project.json
file to https://projects.scratch.mit.edu and submitting each asset to https://assets.scratch.mit.edu
one by one.
To upload the project.json
, make a request to https://projects.scratch.mit.edu
that matches this description:
- The method/URL is
POST https://projects.scratch.mit.edu
. - The
Origin
header ishttps://scratch.mit.edu
. (Actually, you don't need to set this; it just means that, because of CORS, you won't be able to make your own website upload projects from its JS code.) - The
Content-Type
header isapplication/json
. - The
Cookie
header contains your CSRF token and session ID (i.e. it follows the formatscratchcsrftoken={...};scratchsessionsid={...}
). - The body of the request is the
project.json
file's contents.
Upon doing so, you'll get a 200 OK
response that looks something like this:
{
status: "ok"
content-name: "277765566"
content-title: "VW50aXRsZWQtMjgy"
autosave-interval: "120"
}
The main thing you'll find use of here is content-name
, which is the ID of the project.
If you want to update a project.json, rather than upload a new one, just tweak your request's method to PUT
and URL to https://projects.scratch.mit.edu/<id>
. It'll respond with something like this:
{
status: "ok"
autosave-interval: "120"
}
Before uploading a project asset, you'll need to know its MD5 (and file extension); whatever programming language you're using most likely has a utility for getting the MD5 of a file's contents. Once you have that, make a request according to the following:
- The method/URL is
POST https://assets.scratch.mit.edu/<md5>.<ext>
, wheremd5
is the MD5 of the file's contents andext
is its file extension. (Don't even think about sending the wrong MD5 - the server checks! :)) - The
Origin
header ishttps://scratch.mit.edu
. (Again, you don't actually need to set this.) - The
Cookie
header contains your CSRF token and session ID (just like when uploading a project). - The body of the request is the uploaded file's contents.
If the upload was successful, you'll get a 200 OK
response that looks like this:
{
status: "ok"
content-name: "c4e9e84fd9244ca43986c2bdb6669ae8.wav"
}
If your upload is greater than Scratch's file size limit, you'll run into a 413 Request Entity Too Large
error with the following content:
{
code: "PayloadTooLarge"
message: ""
}
There isn't really a concept of updating an already-uploaded asset; you'll just have to upload the file as though it's a totally new asset and update the MD5 referenced in your project.json
accordingly.
Even once shared, Scratch projects aren't necessarily static things. There are several ways to interact with projects.
To mark a project as loved or favorited, you'll want to send a simple POST
request to one of these URLs:
https://api.scratch.mit.edu/proxy/projects/<id>/loves/user/<your-username>
https://api.scratch.mit.edu/proxy/projects/<id>/favorites/user/<your-username>
Of course, these endpoints require authorization.
Since these are /proxy
endpoints, you'll need to specify your CSRF token via both cookie and X-CSRFToken
header as well as your session ID via cookie. (There are also equivalent endpoints without the /proxy/
part, but because of a bug in the Scratch API, these don't send the project creator a notification telling that their project was loved.)
In response you'll get a value like this:
{
projectId: 276660597
userLove: true // or userFavorite
statusChanged: true
}
(The statusChanged
property is always true, even if you'd already loved/favorited the project.)
Checking whether you've already loved or favorited a project is just as simple: just make a GET
request to the same URL (with authorization; also, without the /proxy/
part).
To *un-*love/favorite a project, follow the exact same procedure as adding a love/favorite, but with the DELETE
HTTP method, instead of POST
.
To add a project to a studio, just make a POST
request to a URL in the format https://api.scratch.mit.edu/studios/<studio-id>/project/<project-id>
(with authorization). Removing a project is equally simple - just use the DELETE
HTTP method instead of POST
. In response to a POST
, you'll get an object like this:
{
actorId: "14792872"
projectId: "276660597"
datetimeCreated: "2019-01-09 22:25:12"
studioId: "5542140
}
Making a DELETE
request just responds an empty array: []
.
In either case, what you're looking for is a 200 OK
status code. If you don't have permission to add to that studio, you'll get a 403 Forbidden
error. (Same with removing a project from a studio - unless you're removing your own project, which is always allowed, even if you don't curate the studio.)