# Publishing a resource to the Ignition Exchange How to take a conforming Ignition project and get it onto the Exchange: what file format to upload, how to produce and verify it, and what to put in every field of the upload form. Companion to [`exchange_lint.py`](exchange_lint.py), which tests whether a project follows the conventions, and to the [Exchange Resources Style Guide](Exchange+Resources+Style+Guide.md), which is the source for everything here. --- ## 1. What you upload A **project export `.zip`** — the file Ignition produces from Designer's File → Export, not a gateway backup. | File | Upload as | Notes | |---|---|---| | `.zip` | Package file | The project export. The main artifact. | | `README.md` (or PDF) | Package file | Separate upload — see the warning below. | | Tag export `.json` | Package file | Only if the resource needs tags/UDTs. | | Database dump `.sql` | Package file | Only if it needs a schema or seed data. | | Screenshots `.png` | Images & Screenshots | Optional, strongly encouraged. | > **Never upload a gateway backup (`.gwbk`).** It contains your entire gateway — > datasource credentials, journal profiles, tags, every other project. It is the > wrong artifact and it leaks configuration into a public resource. The Exchange accepts multiple package files, up to 10 MB each. ### The README will probably not be inside the zip Ignition's project export serialises **recognised project resources** — each is a directory containing a `resource.json`. A loose `README.md` at the project root is not a project resource, so the export is expected to drop it. This is reasoning from how the export works, not a verified observation. **Unzip your export and check** before uploading. Either way the guide tells you to upload documentation separately: > **Note:** If you already have detailed documentation for your resource please > note it here and include the documentation file in the Package File upload. Note also that `exchange_lint.py`'s `E-UP-DOCS` rule checks the working directory, not the shipped package. A passing lint does not prove the zip carries your docs. --- ## 2. Before you package ### Run the conformance checker ```bash python3 exchangeResources/exchange_lint.py ``` Zero failures is the bar. Warnings are naming conventions the guide calls "encouraged, not required" — review them and decide, rather than silencing them by contorting the project. Document any you deliberately keep. ### Work the guide's own checklist The guide names four pre-upload checks. Three are often N/A for a journal- or tag-only resource; the first never is: 1. **Check the project export.** Import the exported zip into a brand-new project and confirm it works. Then import it into a project that *already has content* — that is the case the namespacing rules exist for, and the only way to prove nothing collides. 2. **Include the tags.** If the resource needs tags or UDTs, export them and verify the export covers everything the project binds to. 3. **Don't forget database backups.** If it expects tables or seed data, include the dump and name the vendor (MySQL / MSSQL / PostgreSQL) in the description *and* in the install instructions. 4. **Take notes while you test.** Those notes become the Custom Installation Instructions field. Readers range from beginner to intermediate. ### Strip anything internal Search the project for company names, project codenames, internal hostnames, ticket numbers and placeholder text — in **user-visible strings**, not just comments. The linter does not check content, only names and structure. ```bash grep -rniE "yourcompany|internal|localhost|todo|fixme|demo only" ``` Check rendered label text too; a `props.text` value is easy to miss in JSON. --- ## 3. Produce the export **Designer** — File → Export, select the project. **Gateway web UI** — Config → Projects → *project* → Export. Both produce the same zip. If your repo stores projects as unpacked files (gateway-as-files), there is no zip in the repo — you must generate one. --- ## 4. Verify the export ```bash unzip -l .zip # inventory unzip -o .zip -d /tmp/verify-export # extract ``` Check: - **File count** matches the project on disk (minus anything the export legitimately drops). - **Every view, style class and script module** you expect is present. - **`README.md` presence** — confirm, do not assume. - **No stray files**: `.resources/` (gateway-owned cache), `__pycache__`, editor backups. - **No credentials** anywhere in the archive. Then do the real test: import it into a populated project and click through. --- ## 5. Fill in the upload form Fields in the order the Exchange presents them. ### Overview | Field | What to put | |---|---| | **Visibility** | `Public` unless it is genuinely private. | | **Title** | Short, Title Case, says what it does. Usually matches the project title. | | **Tagline** | One sentence. Must **not** repeat the title. | | **Description** | What it does, how it is meant to be used, who benefits, relevant industries. | | **Resource Type** | Closest match from the dropdown, plus a skill level reflecting install/use complexity. | | **Background Image** | Optional colour/design for the resource card. | | **Category** | **Up to 3.** Chosen from: Alarming, Analytics, Connectivity, Dashboard, Diagnostics, Edge Computing, Enterprise, HMI, IIOT/MQTT, MES, Maintenance, Mapping/GIS, Mobile, Monitoring, Reporting, SCADA, Scripting, Security, Simulation, Trending/Charting, Utility. | | **Contact the Developer** | Optional. Your address is never shown; you receive the question plus the asker's address. | | **Tags** | **Up to 10** search keywords. | | **Images & Screenshots** | Optional but highly encouraged — shows what the title and description cannot. | ### Package | Field | What to put | |---|---| | **Version** | `1.0.0` for a first release; later versions auto-increment. **Do not** put the version in the project name. | | **Ignition Platform** | The **minimum** version required. The guide: *"If unsure, select the Ignition platform version in which the package was developed with."* Do not claim a floor you have not tested. | | **Release Tagline** | Short summary of this version's changes. Required even for the first release. | | **Release Notes** | Fuller explanation of what changed and how it affects users. | | **Required Modules** | Any Inductive Automation / Cirrus Link / Sepasoft modules needed. | | **Maker Edition** | Tick if it runs on Maker. Unavailable if you require modules Maker does not support. | | **Other Requirements** | External or custom prerequisites, one per line. Blank if none. | | **Package Files** | The zip, plus docs / tags / SQL as applicable. | | **Custom Installation Instructions** | Step-by-step setup. Assume a beginner. If you shipped separate documentation, say so here and include the file. | The Exchange **auto-generates a readme** from your Description and Custom Installation Instructions, so write both properly. ### Verifying your minimum-version claim Spin up a throwaway gateway at the version you intend to declare and load the project into it. Use a **copy** of the project files — an older gateway rewrites `resource.json` metadata and leaves root-owned `.resources/` artifacts behind. A clean load proves resources parse. It does **not** prove screens render: a component property added in a later version fails at render time, not load time. Open the client and look. --- ## 6. Worked example — Alarm Analysis Dashboard | Field | Value | |---|---| | Title | Alarm Analysis Dashboard | | Tagline | ISA-18.2 alarm performance metrics straight from the alarm journal | | Resource Type | Perspective View — Intermediate | | Category | Alarming, Analytics, Dashboard | | Tags | alarms, ISA-18.2, alarm journal, MTTA, MTTR, bad actors, alarm rate, KPI, dashboard, perspective | | Version | 1.0.0 | | Ignition Platform | 8.1.20 | | Required Modules | Perspective | | Maker Edition | Compatible | | Other Requirements | An alarm journal profile with data | | Package Files | `alarm-analysis.zip`, `README.md` | Needs no tag export and no database dump — it reads the journal through `system.alarm.queryJournal` / `queryStatus` with no journal name, datasource or tag dependency. That portability is what the guide's structure rules produce. --- ## 7. After publishing - **Updates** are new package versions on the same resource, not new resources. Keep the namespace stable so users' imports upgrade in place. - **Never rename the namespace folders** between versions — that turns an upgrade into a duplicate set of resources in every user's project. - Re-run `exchange_lint.py` before every release. - Non-English resources: the guide encourages shipping a language dropdown with English alongside, to widen access.