For developers
Send a layout.
Coverpad opens it.
Coverpad accepts .coverlayout JSON — text, shapes, and photo slots, no embedded images. Hand it off with a custom URL or a shared file. The user confirms, then gets an editable .coverpad document.
Which handoff to use
- URL scheme — best for small, generated layouts from another iOS app, Shortcut, or web page (JSON up to 512 KB).
- File — best for large layouts, downloads, AirDrop, or anything the user should keep as a file.
Do not send a .coverpad package as a public API — that format is internal and includes assets. Always use coverlayout.
URL scheme
Open Coverpad with base64url-encoded UTF-8 JSON in the query string. Coverpad shows a confirmation alert before creating the document.
coverpad://import?layout=<base64url>&name=<optional>| Parameter | Description |
|---|---|
| layout | Required. Base64url (or standard base64) of UTF-8 coverlayout JSON. Max 512 KB decoded. |
| name | Optional. Suggested document base name (path separators stripped; max 64 characters). |
iOS sample project
Download a minimal Xcode app that builds a Hello World! coverlayout (gradient background + centered title) and opens Coverpad withcoverpad://import. Install Coverpad on the same simulator or device, run the sample, tapOpen in Coverpad, then confirm.
Swift
import UIKit
func openInCoverpad(layoutJSON: Data, name: String? = nil) {
let encoded = layoutJSON.base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
var components = URLComponents()
components.scheme = "coverpad"
components.host = "import"
var items = [URLQueryItem(name: "layout", value: encoded)]
if let name {
items.append(URLQueryItem(name: "name", value: name))
}
components.queryItems = items
guard let url = components.url else { return }
// Optional: declare LSApplicationQueriesSchemes = coverpad to use canOpenURL
UIApplication.shared.open(url)
}JavaScript / Shortcuts
Build the same URL and open it. In Shortcuts, use Open URLs with the constructed string. From another app’s Info.plist, add coverpad underLSApplicationQueriesSchemes if you call canOpenURL.
const json = JSON.stringify(layout);
const base64url = btoa(unescape(encodeURIComponent(json)))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const url = `coverpad://import?layout=${base64url}&name=${encodeURIComponent("My Cover")}`;
window.location.href = url;File handoff
Write UTF-8 JSON to a file named Something.coverlayout(UTI ca.maysoft.coverlayout). Then:
- Present
UIActivityViewControllerorUIDocumentInteractionControllerso the user can Open in Coverpad - AirDrop the file to a device with Coverpad installed
- Save to Files and open from there
Coverpad imports the stub into a new editable document. It never edits the .coverlayout file in place.
Format
- JSON snapshot:
formatVersion,pageFormat,elements - Element kinds: text and shapes (including photo-slot placeholders). No images or icons inside the file
- Max file / payload size: 512 KB
- Also useful for humans: Create with AI prompt for drafting layouts
Minimal example
{
"formatVersion": 1,
"pageFormat": "instagramPost",
"elements": [
{
"id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"center": [540, 200],
"content": {
"kind": "text",
"text": "Hello",
"font": { "name": "Helvetica", "size": 48 }
}
}
]
}JSON Schema
Same file as in the app and repo docs. Validate before you send.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://maysoft.ca/schemas/coverlayout.schema.json",
"title": "Coverpad coverlayout",
"description": "JSON-only Coverpad interchange format (text + shapes). No package assets.",
"type": "object",
"additionalProperties": false,
"required": ["formatVersion", "pageFormat", "elements"],
"properties": {
"formatVersion": {
"type": "integer",
"const": 1
},
"pageFormat": {
"oneOf": [
{
"type": "string",
"enum": ["a4", "letter", "youtubeThumbnail", "instagramPost", "story"]
},
{
"type": "object",
"additionalProperties": false,
"required": ["kind", "width", "height"],
"properties": {
"kind": { "const": "custom" },
"width": { "type": "number", "minimum": 150, "maximum": 3000 },
"height": { "type": "number", "minimum": 150, "maximum": 3000 }
}
}
]
},
"backgroundColor": { "$ref": "#/$defs/color" },
"backgroundGradient": { "$ref": "#/$defs/textGradient" },
"elements": {
"type": "array",
"maxItems": 150,
"items": { "$ref": "#/$defs/element" }
}
},
"$defs": {
"color": {
"type": "object",
"additionalProperties": false,
"required": ["r", "g", "b", "a"],
"properties": {
"r": { "type": "number", "minimum": 0, "maximum": 1 },
"g": { "type": "number", "minimum": 0, "maximum": 1 },
"b": { "type": "number", "minimum": 0, "maximum": 1 },
"a": { "type": "number", "minimum": 0, "maximum": 1 }
}
},
"point": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"items": { "type": "number" }
},
"size": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"items": { "type": "number", "minimum": 1, "maximum": 4000 }
},
"textGradient": {
"type": "object",
"description": "Linear gradient for canvas background, text fill, or shape fill. Max 8 colors. angleRadians: 0 = L→R, π/2 = top→bottom.",
"additionalProperties": false,
"required": ["colors", "angleRadians"],
"properties": {
"colors": {
"type": "array",
"minItems": 1,
"maxItems": 8,
"items": { "$ref": "#/$defs/color" }
},
"locations": {
"type": "array",
"maxItems": 8,
"items": { "type": "number", "minimum": 0, "maximum": 1 }
},
"angleRadians": { "type": "number" }
}
},
"shadow": {
"type": "object",
"description": "Drop shadow. offset is [x,y] points; blurRadius ≥ 0.",
"additionalProperties": false,
"required": ["color", "offset", "blurRadius"],
"properties": {
"color": { "$ref": "#/$defs/color" },
"offset": { "$ref": "#/$defs/point" },
"blurRadius": { "type": "number", "minimum": 0 }
}
},
"element": {
"type": "object",
"additionalProperties": false,
"required": ["id", "center", "content"],
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"center": { "$ref": "#/$defs/point" },
"content": {
"oneOf": [
{ "$ref": "#/$defs/textContent" },
{ "$ref": "#/$defs/shapeContent" }
]
}
}
},
"textContent": {
"type": "object",
"additionalProperties": false,
"required": ["kind", "text", "font"],
"properties": {
"kind": { "const": "text" },
"text": { "type": "string", "maxLength": 512 },
"font": {
"type": "object",
"additionalProperties": false,
"required": ["name", "size"],
"properties": {
"name": { "type": "string", "minLength": 1 },
"size": { "type": "number", "minimum": 8, "maximum": 400 }
}
},
"style": { "$ref": "#/$defs/labelStyle" }
}
},
"shapeContent": {
"type": "object",
"additionalProperties": false,
"required": ["kind", "shapeKind", "style"],
"properties": {
"kind": { "const": "shape" },
"shapeKind": {
"type": "string",
"enum": [
"rectangle",
"circle",
"oval",
"pill",
"triangle",
"octagon",
"heart",
"star",
"conversation",
"arrow"
]
},
"style": { "$ref": "#/$defs/shapeStyle" }
}
},
"labelStyle": {
"type": "object",
"additionalProperties": false,
"properties": {
"textColor": { "$ref": "#/$defs/color" },
"shadow": { "$ref": "#/$defs/shadow" },
"outline": { "$ref": "#/$defs/outline" },
"gradient": { "$ref": "#/$defs/textGradient" },
"decoration": {
"type": "object",
"additionalProperties": false,
"required": ["underline", "strikethrough"],
"properties": {
"underline": { "type": "boolean" },
"strikethrough": { "type": "boolean" },
"color": { "$ref": "#/$defs/color" }
}
},
"background": {
"type": "object",
"additionalProperties": false,
"required": ["color", "cornerRadius"],
"properties": {
"color": { "$ref": "#/$defs/color" },
"cornerRadius": { "type": "number", "minimum": 0 }
}
},
"rotationRadians": { "type": "number" },
"textAlignment": { "type": "string", "enum": ["left", "center", "right"] },
"opacity": { "type": "number", "minimum": 0.1, "maximum": 1 },
"isBold": { "type": "boolean" },
"isItalic": { "type": "boolean" }
}
},
"shapeStyle": {
"type": "object",
"additionalProperties": false,
"required": ["displaySize"],
"properties": {
"displaySize": { "$ref": "#/$defs/size" },
"fillColor": { "$ref": "#/$defs/color" },
"gradient": { "$ref": "#/$defs/textGradient" },
"opacity": { "type": "number", "minimum": 0.1, "maximum": 1 },
"outline": { "$ref": "#/$defs/outline" },
"shadow": { "$ref": "#/$defs/shadow" },
"rotationRadians": { "type": "number" },
"isPlaceholder": { "type": "boolean" },
"placeholderText": { "type": "string", "maxLength": 35 }
}
},
"outline": {
"type": "object",
"additionalProperties": false,
"required": ["color", "width"],
"properties": {
"color": { "$ref": "#/$defs/color" },
"width": { "type": "number", "exclusiveMinimum": 0 }
}
}
}
}