- A collection is a table:
create_collection({ slug, name, schema }), rows withcreate_collection_row/create_collection_rows(up to 500, all-or-nothing) /import_collection_csv, edit withupdate_collection_row,update_collection_schema(schemareplaces ALL fields:get_collectionfirst). Field types: text, number, boolean, date, select, image, url, email, color, richText, media, json. Read rows in a page as{% for row in collections.<slug> %}withrow.<fieldKey>(richText fields need| raw; an image or media field is a mediaId:{{ row.photo | image_url: width: 800 }}). Filtered, searched and paged lists: theliquidtopic, "Lists from the URL". A detail page:update_page({ pathPattern: ":slug" })and{% assign row = collections.team | where: 'slug', request.params.slug | first %}. - Gating (
update_collection_schema):requiredPlans: ["pro"]shows the rows only to members of those plans;requiresCustomerLogin: trueto any signed-in customer. A page that reads a gated collection is rendered per visitor, not served as a shared file. - Per-row lock: add a text field with the key
requiredPlansand write comma-separated plan slugs on the rows to lock. A visitor without one of those plans still gets the row, minus the fields named inmemberFields(keys of the schema;[]clears), withrow.lockedtrue:{% if row.locked %}<a href="/pricing">Join to watch</a>{% else %}{{ row.video }}{% endif %}. - Webhook feed (Business and up):
set_collection_webhook({ slug })turns a manual collection into a feed (or passsource: { type: "webhook-feed" }tocreate_collection).get_collectionthen shows the ingest URL and how senders sign a POST; rows upsert byexternalId.rotate: truemints a new secret (shown once; the old one stops working): hand it to the sender. A collection syncing from Sheets or Airtable can't be converted. - Vacation rentals (Hospitable) (Pro and up):
connect_app({ app: "hospitable", inputs: { token } })with the token the owner gives you (or they paste it on the Apps screen) makes thepropertiescollection and syncs; the fields fill in on the first sync. Each row is a home:title,slug,summary,description,picture(a full URL;| image_url: width: 900passes it through),photos(every photo,{ url, thumbnail, caption }in order; the detail block shows them as a gallery with a full-screen viewer and a photo tour, grouped by room when the owner adds a multiline text fieldphotoRooms: one room per line in photo order. Fields the owner adds survive syncs),city,address,latitude,longitude,maxGuests,bedrooms,beds,bathrooms,amenities(list),petsAllowed,checkIn,checkOut,listed,fromPrice(cents) /fromPriceFormatted,nextAvailable,bookingUrl(empty when unset: wrap the Book button in{% if home.bookingUrl %}), andcalendar: one entry per night,{ date, available, price, priceFormatted, minStay, noCheckin, noCheckout }. Guests pick dates by tapping the detail block's calendar. With checkout on for the collection (set_checkoutwithfieldMap: { capture: "hold" }to approve each stay) they book and pay on the page, charged the picked nights' prices; otherwise the Book button links tobookingUrl. Pages: blockrental-homes-gridon a list page (/stays) andrental-home-detailon a page named "Stay" withpathPattern: ":slug"(cards link to/stay/<slug>). Dates across homes:get_calendar,set_dates(close, reopen, retry a date the rental tool missed),share_calendar_link(the link Airbnb, Vrbo and Booking.com import). Bookings and payments:list_orders/get_order/update_order(seeintegrations). - Other apps fill collections the same way.
list_appsshows each one, what it needs and what is connected;connect_appconnects one with the key or link the owner gives you (or they use the Apps screen);sync_collectionreads it again. Then build pages on the collection. Hostaway and Guesty write the samepropertiesshape as Hospitable; Airbnb, Vrbo and Booking.com calendar links do too, with dates only (the owner adds photos and text). Events (Google, Outlook or Apple calendar links, Eventbrite, Ticket Tailor) go inevents:title,start,end,allDay,startDate,endDate,startTime,endTime,timezone,location,description,url,calendar, plusimageandticketUrlfrom the ticketing tools; blockevents-upcoming. Blog posts (an RSS feed: Substack, Ghost, WordPress, Medium) go inposts:title,link,date,summary,image,author; blocklatest-posts. Cal.com open times:title,start,end,startDate,dayLabel,startTime,endTime,timezone,link(books that time),eventType; blocknext-open-times. Google Sheets, Airtable, Notion, Supabase, Baserow and NocoDB keep the table's own columns: readget_collectionfor the keys. YouTube videos go invideos(the posts fields plusvideoId; blocklatest-videos), podcast episodes inepisodes(plusaudioUrl,duration; blockpodcast-episodes), Bluesky and Mastodon posts inposts. Shopify, WooCommerce, Square, Gumroad and Lemon Squeezy fillproducts(the Stripe product shape plusbuyUrlandstoreName): the product blocks show "Buy on <store>" for those rows instead of the cart. Form posts can also go to an email list, CRM, chat or task tool (Mailchimp, HubSpot, Slack, Trello, Asana and others), set by the owner on the Apps screen; the form markup doesn't change. Tracking and live chat (TikTok, Clarity, Plausible, Crisp, Intercom…) areset_integrations, never hand-written script tags.