Shareshot Update — Month 2

Making of Shareshot

A quick update on month two of Shareshot… with the launch on 12th August we’re just over two months in now. A big milestone was passed a couple of days ago, namely 10,000 framed screenshot exports, a pretty astounding number to see so early in the app’s life!

Screenshot of our telemetry showing over 10,000 exports

A big number

The iOS 18 release which included frames for all the new devices and a Control Centre and Lock Screen Control Widget got us a really significant boost in downloads and purchases which lasted about three weeks:

A sales rollercoaster

We have no doubt that the nice bump from September 16th to October 7th was driven largely by reviews we received for the 1.1 release. We were lucky to get featured by MacStories talking about journalling home screens, a MacStories post about control widgets and also in AppStories podcast. We were also featured in a Stephen Robles YouTube video about iOS 18 app updates and possibly some others we’re not aware of. We’re very grateful to everybody who has helped spread the word! (And yes, this chart has a Y-axis! 🙀 #buildinpublic).

Even after the bump calmed down we’ve seen a nice increase in exports per day, circa 200/day vs. 100/day the first month after launch.

In month 2 we’re around 150 DAUs currently compared to roughly 100 DAUs in the first month since release and the whole month of September saw just under 3000 MAUs.

It’s still a gentle start but we’re growing!

On the development front, we’ve got a 1.1.3 bug fix release due in the next few days and work on 1.2 is underway. That release will introduce some more background options and internal plumbing for bigger changes to come in 1.3!

We’ll report back again soon…

Shareshot’s Launch Week

App Release / iOS / Making of Shareshot
Size screenshots of the app Shareshot

On August 12th we launched our app Shareshot which makes it easy to add frames and backgrounds to screenshots or other images.

Finally. Our fourth released indie app actually does some numbers.

The launch went way beyond our expectations. We have had over 2,500 installs in just this first week and well over 1,600 screenshot images have been exported or shared (our metrics were not reporting this initially). We have been really touched by the level of support from the development community and the wider pool of Beta testers, of which there were over 600.

We were lucky to be featured in both 9to5Mac and MacStories.

I am sure the launch went so well in part because of this strategy. We ran a wide open public beta from just before WWDC in June, and ran a pre-order in the App Store in the week before launch. We had something like 400 pre-orders by launch day for a free app! This definitely helped with launch week App Store and search rankings as well as word-of-mouth and general social media vibe — we had things to post about repeatedly for the benefit of all.

As a result of this we were also able to pre-promote the Introductory Offer Subscription that was available during launch week with circa 35% discount for the first year’s worth of subscription.

In fact, we put a little “PRO SALE NOW ON” button in the UI that automatically shows only when there is a discount available in the App Store (using StoreKit 2 APIs via RevenueCat) so it will be disappearing shortly. Tapping it would bring up the paywall showing the promotional offer — a voluntary action before people even hit the paywall. This was responsible for 30% of our subscription sales in the first week.

Downloads and Purchases

Downloads are still healthy at around 50 per day, far more than any of our previous apps, and this is despite not having great chart or ASO rankings yet. The search rankings are improving slowly it seems.

Our chart rankings were pretty good – top 100, top 50 in some countries for a short time. This was likely due to the weighting Apple introduced for new apps but also the initial launch’s wave of attention leading to high downloads. Now we are rapidly tanking towards 500+ even with ratings and reviews now coming in. Currently best position is #92 in Brunei Darussalam so there’s that.

In terms of ratings and reviews, we’ve only received 20 ratings and 6 reviews so far. Partly this is because our review prompting code deliberately will not kick in until at least 3 days after the first run of the app, and we can see it is prompting people now so hopefully this improves so that our search ranking will increase.

Interestingly, throughout the week the number of purchases as a % of installs has remained really quite static, so this “Bezos-chart” without numbers on it (we’re definitely not retiring any time soon, but we are not complaining!) shows the shape of the launch from August 13th in terms of downloads and purchases. The last day is incomplete, so it’s lower than it likely will end up. What remains to be seen is whether this level holds when the launch week sale ends!

We’ve generated enough revenue that for August at least, we have to (gladly) pay TelemetryDeck and RevenueCat for their services! We also had to increase our RCKit app subscription to keep receiving notifications + stats from RevenueCat in their iOS app. A nice problem to have!

Vision or mirage?

The jury’s still out! We put a lot of work into the Vision Pro version of the app and it remains my favourite version of the UI though I need to improve it quite a bit as I learn more about the ergonomics of using Vision Pro. It does look great when you show colourful content on a Vision Pro. However… so far we have only 19 users (and I’m one) and 4 of them are paid users! We were not expecting any significant sales on this platform initially, but hopefully being there early will lead to better things.

A huge thank you

We really are so grateful to everybody who has supported us making and shipping this app and for all the enthusiasm, lovely comments and feedback we’ve received.

We feel we have a really solid foundation to build upon now with Shareshot, and we have some great features that we can’t wait to start building for you!

Confused by appintentsmetadataprocessor errors in Xcode 16?

Development / iOS

I’m currently building a new app for framing screenshots and adding backgrounds for social sharing called Shareshot that is in public Beta. It supplies a bunch of App Intents for Shortcuts integration so that you can batch-frame screenshots.

I tried building it with Xcode 16 betas and found a bunch of confusing build errors for code that builds fine in Xcode 15. You might bump into them too:

2024-07-18 21:33:51.168 appintentsmetadataprocessor[48853:35754477] Starting appintentsmetadataprocessor export
2024-07-18 21:33:51.204 appintentsmetadataprocessor[48853:35754477] error: At least one halting error produced during export. No AppIntents metadata have been exported and this target is not usable with AppIntents until errors are resolved.
error: Found multiple, identical identifiers for query: Query, each identifier must be unique

I was confused by this message. It uses “query” multiple times — I got a lot of them — and initially I just thought this was some straight-up new bug in appintentsmetadataprocessor which is part of the toolchain that processes your App Intents Swift source to extract static elements at build time, to build a JSON file containing metadata about your intents and bundles it into your app.

Eventually I worked out that the capitalised Query was the name of the nested query types used by several AppEntity types in my code:


public struct BackgroundOption: AppEntity, Equatable {    
    public var id: String { value.id }
    public let value: BackgroundInfo
    
    ...
    
    public static var defaultQuery = Query()
    
    public struct Query: EntityQuery {
       ...
    }    
}

I was advised that as of Xcode 16 the type name used for the query type in AppEntity(s) must be “globally” unique and the tooling does not use the fully qualified name of the type if it is nested, contrary to standard Swift scoping. This does seem to work fine in Xcode 15 so it is unclear why this has regressed.

The error was occurring for me as I have several AppEntity that use this same pattern, all using the same locally-scoped Query name — if I had only one it wouldn’t have happened. The workaround is to uniquely name all these nested types, e.g:


public struct BackgroundOption: AppEntity, Equatable {    
    public var id: String { value.id }
    public let value: BackgroundInfo
    
    ...
    
    public static var defaultQuery = BackgroundOptionQuery()
    
    public struct BackgroundOptionQuery: EntityQuery {
       ...
    }  
}

It’s annoying but it’s not a huge problem, if a little confusing at first. It does make me wonder that if I have another global type BackgroundOptionQuery I’ll get other weird build failures if it doesn’t also conform to EntityQuery.

I raised a feedback about this, and received the response that this “Works as currently designed”. So it looks like we need to change our code for Xcode 18. (FB14375756 “appintentsmetadataprocessor fails to process AppEntity with nested query types”).

Hopefully this saves somebody some time.

My Mac History

Apple / Musings
Photo of an original Mac running Through The Looking Glass

Everybody posting their 40th Anniversary of the Mac stories obviously prompted me to write this, which is a roundabout Mac journey. In hindsight the Mac clearly had its effect on me even when I wasn’t using it…

I grew up in Kingston, South West London. Very popular at the time for its affordable/renovatable semi-detached Victorian houses which are now largely unaffordable to normal people. I didn’t know it at the time but I saw what I presume was one of the first ever Macs in the UK, in our house.

Read More