Albums are now faster when hosted at

A few weeks ago we enabled HTTP/2 for all albums hosted here that are using https. This is done automatically, so there is no need to upload your albums again. Just make sure you access your albums using https.

Using HTTP/2 makes the albums load much faster, especially over long distances. We have checked what HTTP/2 makes to the load times of an album with 500 images in a folder. The album in this example had to travel across the globe (between Stockholm and Australia) and using HTTP/2 clearly makes a difference:

A looping video when fetching the same album from half across the globe using HTTP/1.1 vs HTTP/2.

Previously HTTP/1.1 was used which has been around since 1997. The new version called HTTP/2 makes better use of the TCP connections between the browser and server so multiple resources can be fetched simultaneously by each connection instead of only one at a time which HTTP/1.1 could do. The browser could open multiple connections when using HTTP/1.1 to load resources more efficiently, but having to handle multiple connections puts a strain on all the network resources from the client computer, via routers to the web server, so browsers usually open at the most just a few connections to each domain. Tricks to spread the resources on a web page to different domains can be used. But this can't be done for albums, since all the resources (except maybe JavaScript libraries and fonts) have to be loaded from the one domain the album is hosted on.

When using HTTP/2 this is no longer an issue, since each connection can be shared among many resources. This also means that HTTP/2 lowers the effect of high latency ("long ping times"). The jAlbum servers are located in Sweden, so within Europe the latency is quite low (usually less than 40ms). But when viewing an album from another continent, the latency can be several 100ms. As seen in the example above HTTP/2 minimizes the effect of this so albums fetched over long distances are a lot faster. This is important for our users in America and Asia. Tests run by users in the US have shown that load times for a typical album went from 4.5 seconds to 2.4 seconds. A dramatic difference!

So, all you have to do is to make sure the URLs you use for your albums hosted here start with https, and then your albums will be quicker too. If you are using an old account profile in the jAlbum desktop software at Tools->Upload/Manage... it might say that the "Web address" starts with http. Then just Remove that account profile and Add it again.

Which jAlbum skin?

While jAlbum comes with 8 preinstalled skins, you can find dozens more in our skins section. As shown on the chart below, most users simply stick with the default skin, or whatever the default was when they first installed jAlbum. Turtle still holds second place, even though we retired it years ago and released Tiger to replace it. And then there’s Chameleon, which was deprecated over 10 years ago – an eon in web design – but still sits peculiarly in 4th place. We’d like to encourage you to try out other skins; hence this blog post.

What’s wrong with old skins?

I know it’s a pain changing the skin when you are building a large gallery and want to add new albums every now and then. It looks odd when the older albums use a different skin. However, times are changing, new devices appear with different screens and different capabilities, there are new standards, new browsers emerge, and those old albums become almost unusable on these new devices. The single most important change of the past decade in web design is the rapid spread of mobile devices. Today more than 50 percent of site visitors use a mobile device. These not only have smaller screens, but also don’t have a pointing device (i.e., a mouse), which might render old albums a pain to navigate. That’s why all new skins are based on responsive web design, which allows the album to adapt to the visitor’s device. This is what sets Turtle apart from Tiger, for example.

Using a modern skin is not only important for the visitors’ sake, but Google and other search engines give a higher rank to web pages that embrace modern standards.

Historically, there were also some Flash-based skins in our skin repository, like the once very popular Fotoplayer skin. But Flash no longer works in any current browser, so we’ve removed all of the Flash skins.

Naturally, if you don’t care about mobile visitors, there’s nothing wrong with old skins. But even on desktops and laptops, you might have problems with integrations. PayPal, Google Maps, and Facebook might no longer work; these external services retire their old interfaces (API’s) regularly. This happened with Google Maps in 2017, for example, and with Facebook sharing after the 2016 US election.

Desktop Mobile

Once a skin gets to the point where its underlying technology gets hopelessly dated, we can either choose to rewrite the skin from the ground up, or to bring out a new skin that mimics the old one. Tiger inherited most of the features, styles, and layout from Turtle. Development of the hugely popular Chameleon skin was halted a decade ago with no descendant. I know this disappointed quite a few users. The good news is that we are planning on renewing Chameleon this year.

Which skin is good for me?

It boils down to what type of content you usually create. For complex, multi-level albums it’s wise to choose a robust skin with strong navigation support and search. For single events it might be better to choose a lightbox-first skin that's built around the slideshow, although not as useful for navigating deeper folder structures.

If you’re after the simplest presentation, and the extra features are not important, you can choose a “minimalistic skin”, like Minimal or Atom. Athough they look similar, Atom features a fully-responsive layout, and has more options. These skins are also the easiest to tweak, or to use as a base for creating a new skin.

In the middle ground stands the Projector skin. It appears in the second table here because it’s a “lightbox first” skin, but it uses a database, which allows functions like Search and Tag cloud work. So, it also works well for large albums.


Index page first skins

  Fancybox Mars Tiger Photoblogger Pluto Story
Sample album
Created 2018 2019 2017 2014 2018 2020
Number of styles 7 15 26 12 11 10
Deep (collapsible) navigation menu    
Search within album      
Tag cloud (keywords)      
Thumbnail layout Masonry Grid, Masonry Grid Vertical, Grid, Masonry Grid, Masonry Masonry
(alternating size)
Background music    
Full screen
Theme image support
Displays "New" tag    
Custom web pages    
Web locations
Plays video files
Audio files    
Other file types (e.g. PDF)    
Animated GIF's      
Swipe support
Displays map    
Panorama support    
360° panorama    
Displays metadata    
Face tags      
Shopping cart      
Feedback / Kiosk      
Social sharing    

Lightbox-first skins

  Animatics Comet Lucid Projector
Sample album
Created 2019 2018 2019 2018
Styles 7 1 9 27
Transition effect(s) Ken Burns, Cross-fade,
Zoom, Stack
Cross-fade Slider carousel Zoom, Ken Burns,
Stack, Slide, Swap,
Flip, Book, Cube
Swipe support  
Background music  
Tag cloud      
Displays metadata  
Displays map
Displays videos  
Social sharing  
Custom pages  

Special skins


Responsive is the only one which can create a whole album inside a web page on-the-fly by utilizing Javascript. This is useful when you just want to display a handful of pictures in an already-made web page.


Mercury is special because it is capable of displaying lengthy text around images, not just below.


Story is the first skin capable of playing with thumbnail sizes (thumbnail / wide / full), in order to create an intriguing blog-like experience. This skin was also the first that allowed embedding custom pages (or any custom content) into the index page, which strenghtens the blog-like experience even further.


Zigzag is another example of an unusual layout. It alternates the left/right positions of the pictures and their captions.

Embedding albums in other pages

Unfortunately, on mobile devices you can easily end up with an unusable album when you use the traditional “IFRAME” method. As the IFRAME element has to be a fixed pixel size, the album area often stretches beyond smaller screens, effectively making it impossible to scroll through the page, or to reach navigation elements. The “responsive embed code” utilized by a few skins still can only match the width of the screen. The album can still stretch beyond the screen when the mobile is held horizontally.

The only user-friendly way is to run the album in its own tab or window, i.e., linking to the album from your site instead of embedding it. I know this way your site’s menu or header is not included, but it’s still better than showing a broken page. Our skins are usually easy to tweak to match your site’s theme, and many provide ways to include custom elements (e.g. header, footer) in the album.

The other possibility for WordPress users is to use our jAlbum bridge component, which pulls images from an uploaded album, and displays them in a “projector” box within the post.

Finally, the Responsive skin – mentioned above – is also capable of creating a little album inside another web page by utilizing only Javascript. This skin generates a call code you have to insert in your page.

General advice using skins

If you’d like to experiment with different skins don’t do this on your production project! The skin settings usually do not survive switching back and forth between skins. Create a small sample album, and experiment on that. You can also create a duplicate of a project by choosing File → Duplicate project.

Before you run a skin update make sure to save the current project. It is rare for jAlbum to lose the settings during a skin update, but you might end up with zeroed settings (first option, false, empty, black color). If this happens, do not save the project! Simply close the project without saving it, then reopen it. You might lose the latest changes, but at least not all. It is safest to install a skin update without an open project.

To discover more skins follow this link to our Skins section. jAlbum’s skin chooser box also has a link at the bottom of the list; read “Download more skins...”, where you can find skins by features too.

Comments are welcome,

Skin development news 2021/02

It seems whatever might happen around us, we never stop bringing new features to jAlbum and our bundled skins. :) Most of these ideas came from our helpful community which is a tremendous help for us, the development team. Here are a few new things added recently:

Continuous zoom, zooming into the original image

When you aim to show the finest details in a photo the web-optimized slide images are often too small. With this new continuous zoom tool the skin can load the high resolution version on the fly when the visitor zooms enough into an image. However, loading a sizeable image (e.g. a 64 MB panorama image) can be hard for both the graphics system and also regarding the load time. So you might want to optimize (downsize) such images beforehand you add them as “original”.

This function has been made available first in Story skin, but Photoblogger will follow soon. You can use Ctrl + mouse wheel and Numpad + / - buttons too, besides the slider handle below the zoom button:

Skip between levels with previous / next folder links

Originally my skins only jumped to the next folder of the same level. Consequently an automatic slideshow has always stopped at the first time when it didn’t find an adjacent folder. Now the “Skip folder levels” option allows jumping levels up and down. This happens also when you go beyond the last image in a folder (in the lightbox), this way the slideshow won’t stop at the middle of a complex album.

Ask permission to enter a folder

If you’d like to showcase photos not suitable for children, it’s good to have a popup that asks the visitor to confirm his/her age. To make this happen all you have to do is adding a variable, called askPersmission in Edit mode’s right side “Variables” panel. See below!

Select the folder → Edit mode → Variables panel

This is what pops up in the album. (default)

You can also customize these texts by adding value to the variable (right to the name). Format: TitleText::QuestionText::AllowButtonText::DisallowButtonText.

Of course kids can simply click “I’m over 18”, but this is at least a decent attempt to detour them. If you need to set up a strict policy, the only way to do this is by adding password protection to folders through the server’s Control panel. A web page cannot provide any such protection from inside, because anybody can read the folder's URL from the source code.

Better support for media files and practically any file format beyond JPG

As a starter I always design my skins for regular JPG’s – as that makes up 99% of the albums. However, jAlbum albums should be capable of handling videos, PDF’s, moving GIF’s and such, which not always work out-of-the-box, or at least doesn’t work optimally. To test different file formats, and different image types I have set up a test album – you can also peek into:

Related: Using THM files for media (as poster image)

THM files were invented at the early days of jAlbum to provide poster images for video files. Ever since jAlbum is capable of recoding videos and extracting thumbnails, this feature has diminished in importance. Unless you’d like to use an external image, like a real movie poster, or with audio files, which do not have visual representation otherwise. All you have to do is to add a JPG file renamed with the same base name as the media file, use the extension “thm” (e.g. sound.mp3 → sound.thm) and place this file into the Image directory’s appropriate folder. Note, if the media file is linked (i.e. not copied directly into the Image directory) you still have to use the Image directory (Ctrl-Shift-I) – due to historical reasons – otherwise jAlbum will not pick up the THM file.

Related: Using sound clips

Sound clip support is a special feature of some skins (Tiger, Story and Photoblogger for example) by which you can add sound to an otherwise silent photo or video. You should add the mp3 file named the same as the image or video but keep its original “mp3” extension. You need to place this file in the file’s original (linked) folder, otherwise if it’s placed in the Image directory jAlbum will add as separate sound file.

In case of videos sound clips play independently, although the skin tries to synchronize their start/stop events. Here’s an example of such a video enhanced with a sound clip.

In order to check out this sound clip you’ll have to start from the index page; go down the page bottom, and click the “expand” button on the video’s top right corner!

Many users ask why videos (or the background audio) won’t auto-start in their albums. The bad news is, this is by design. Browser makers started to block video auto-start (with sound) in 2019, in order to silence obstrusive ads. This means visitors have to click the “Start/Play” button the first time, even though the gallery author has asked the skin to start videos automatically. Once the visitor has started any video in the album, the next will auto-start, fortunately. The browser maintains the “engagement index” to know which sites the visitor trusts in this regard. You can read more about this “feature” here.

Hiding GPS location

Showing off GPS location publicly might raise security concerns. For instance I wanted to mask my flat’s location in the sample album. Unfortunately, mobile photos do almost always have this GPS data embedded, it’s not enough to trash it through the Edit mode’s Location panel alone. So there is a new setting in Story and Photoblogger skins in the “Image data” panel (above the mentioned Location panel) - called “Hide GPS location”. By using this you can avoid placing the GPS location of a photo on the album’s map.

... and one more thing

We are aware how popular our Chameleon was amongst our users. Unfortunately, Chameleon skin was based on the – since outdated – “table design”, which made the further development practically impossible. Now – due to massive demand :) – I decided to rewrite Chameleon from ground to make it modern and responsive. It’ll take a few months, but hope you’ll appreciate the effort.

Comments are welcome,


Automate it!

It's sound human nature to avoid doing repetitive tasks. jAlbum was once developed as I didn't want to manually prepare 120 images for the web and create the needed html. Even if jAlbum has a good number of batch processing features, you may find yourself doing manual repetitive work, for instance deleting 1-star images, looking for broken links, renaming files, changing comments or looking for certain images (panoramas for instance). If there is ANY pattern to the work you're doing, then you can automate it using jAlbum's flexible scripting environment. Your aim might not even be to create a web gallery but simply to give your images more descriptive names than "IMG_6624.JPG". How about letting jAlbum rename such images in the format cameraModel+location for instance? I mean, a file called "iPhone SE-New York-7.JPG" tells me A LOT more than "IMG_6624.JPG", don't you agree?

With jAlbum's scripting environment (Tools->System console), you can automate such tasks with only a few lines of code, preferably in the easy-to-learn Groovy language or JavaScript. Long running tasks will automatically pop up a progress indicator allowing you to abort the task, and most operations (not deletions) can also be undone in one go if you change your mind.

Without further ado, let's go through some examples (Nothing beats learning by example). The following scripts operate on all items of the currently opened project, but they can easily be modified to operate on the current folder only, or selected items/objects only (see further down). To try these scripts, copy and paste them to the upper panel of jAlbum's system console (one at a time), then hit the Execute button (CMD/CTRL+E) to execute them (you can also select a part of a script to execute and hit Execute). The result is printed to the lower panel.

Here are some examples to glance at, explanation follows:


Sample scripts (Groovy language, requires jAlbum 22)

// Exclude 1- and 2- star images
.forEach(ao) -> {
    if (ao.rating == 1 || ao.rating == 2) {
        ao.included = false;
        println ao


// Change 4-star images to 5 stars
.forEach(ao) -> {
    if (ao.rating == 4) {
        ao.rating = 5
        println ao


 // Exclude videos
.forEach(ao) -> {
    if (ao.category == {
        ao.included = false;
        println ao


// Find broken links
.forEach(ao) -> {
    if (!ao.file.exists()) {
        println ao.file

I hope you find this fairly intuitive. Let's break it down:

  • "Work" is the Java class that's responsible of most of the "plumbing" in these scripts (boring common code): It handles the processing of multiple objects (of any kind actually) and can even process multiple objects simultaneously. In case processing takes time, it pops up an abortable progress dialog. The executed operations are grouped in "undo groups" so it's enough with one (or a few) undo operations to undo all operations. Finally, "Work" makes it easy to prompt the user before action starts and report results.
  • ".on()" - This method tells Work what objects to work on. It can be either an array, List or Stream of objects (i.e. images, videos etc). Typical arguments are as follows:
    • rootFolder.descendants - All objects in the current project
    • currentFolder.children - All objects in the current folder
    • currentFolder.descendants - All objects under the current folder (i.e. including sub folders)
    • selectedObjects - The selected objects
    • TreeCollection.of(selectedObjects) - Selected objects AND their descendants (sub folders)
Note: Excluded objects are skipped when referring to "descendants". To also include these, refer to the TreeCollection API.

  • forEach(ao) - Code to execute for each encountered object. "ao" is a shorthand for AlbumObject - the API used to interface with objects of a project. Check out the documentation for this API in order to know what operations you can perform on each object.

Let's move on with slightly more complex things. Here's first a script that demonstrates how to pass a filtered stream of objects to Work. In this case 1-star rated objects. This script also prompts the user before proceeding and finally shows a result dialog:

// Delete 1 star images. Prompt user and print result
Work.on( -> ao.rating == 1))
.ask("Ok to delete all 1 star images?")
.forEach(ao) -> {

// Find links
.forEach(ao) -> {
    if (ao.file instanceof LinkFile) {
        println ao.pathFromRoot

This following script uses the gotoPath() method to navigate the user to the first object found that has a broken link. It also demonstrates how to abort further processing once this first broken link is found:


// Goto first broken link
.forEach(ao) -> {
    if (!ao.file.exists()) {
        throw new OperationAbortedException()


// Print images and their sizes
.forEach(ao) -> {
    if (ao.file.exists() && ao.category == Category.image) {
        println ao.pathFromRoot + ": " + ao.ImageInfo

// Find panoramas (i.e. images having a width 2 times the height or more)

.forEach(ao) -> {
    if (ao.file.exists() && ao.category == Category.image) {
        if (ao.imageInfo.width >= ao.imageInfo.height * 2)
        println ao.pathFromRoot

// Replace texts in comments. Look for "Adria" and replace with "Kabe"
.forEach(ao) -> {
    ao.comment = ao.comment.replaceAll("Adria", "Kabe")
    println ao

Here's a pretty powerful file renaming script: It uses an online location service to map GPS coordinates embedded within images to rename images to the format cameraModel-Place-number. As looking up locations based on GPS coordinates over an external service may be time consuming, this script uses the parallelStream() call to process objects in parallel, and because of the parallelism, we're using an AtomicInteger as number counter to get truly unique numbers for each file:

// Rename files by camera model and place
import java.util.concurrent.atomic.*
counter = new AtomicInteger(1)

.forEach(ao) -> {
    if (ao.category == Category.image) {
        PlaceService.Place place = PlaceService.instance.getPlace(ao)
        if (place != null) {
   = ao.vars.cameraModel + "-" + + "-" + counter.getAndIncrement()


Finally, here's a script that similar to an SQL group-by and order-by, it finds all keywords and presents them by name and number of occurrences, starting with the most common keyword. It uses some pretty powerful Java Stream API calls:

import java.util.function.*;

// Present keywords by name and occurrences

result = -> ao.keywordSet).flatMap(ks ->
    Function.identity(), Collectors.counting()

// Now sort it

result.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed())
.forEachOrdered(e -> println e)


 Save scripts as "Tools"

If you've made a handy script that you'd like to execute several times, put it into a text file named "preferred name.groovy" and place that file under a "tools" sub directory of jAlbum's "config" directory (See Tools->Open directories->Config directory). Now this script can be executed under the Tools->External tools menu (requires a restart to show up). You can find more useful "External tools" under the "tools" folder of jAlbum's program directory. Inspect these for more inspiration.

I hope this inspires you to investigate the power that lies within jAlbum's scripting environment. You'll find more developer help in our developer center. If you get stuck, post questions to our forum. If you make an awesome script you think others would appreciate, share it in our forum.

What's new on the skin development front?

While we often communicate what’s new with jAlbum, only a few of you follow the advancements in skin development by reading those hidden skin update logs. Here you are some of the most interesting new skin features.

It all started with Story skin, which made custom pages even more useful, by allowing them holding just any (textual) content. This combined with the ability to mix them into the images allowed authoring complex, blog-like webpages, that barely resembled the conventional, square thumbnail grid galleries.

This change, however, made custom pages look broken after changing skins. I realized this when I made a modern sample album, but it turned ugly playing with skins. I guess this is what most new users do too, and might hit user experience badly.

So I revisited all of the bundled skins and modernized them. Tiger skin is still to be done, but Animatics, Lucid, Photoblogger, Projector and Story has received substancial updates recently. Besides changing the custom page layout a lot of other improvements were implemented. Some of these were deep changes like an organ transplant. Hopefully this will result in up-to-date skins, matching modern browser design, that will be also easier to maintain in the future. Here are some of the highlights:

Instant preview on the User Interface

After discovering small browser windows can be embedded into the user interface, I started adding this component to my skins. This makes the effect of certain skin settings instantly comprehensible, saving a lot of guesswork for users.

Custom pages

Embedding custom pages into the index page is now possible with Photoblogger skin too. In the future this possibility will also be added in Projector and Tiger skins.

Embedded custom pages in Photoblogger (embedded). See the same in Story skin!

New custom pages: Calendar and Newimages are now available with all these skins. Calendar collects all images into a calendar-like layout with links to the original folders, while Newimages collect all images created (or modified) within a timeframe. Let me remind you these custom pages work the best placed at the top level, and instead of renaming the file, it’s much better using Title to provide any text as title, e.g. “New images”, which is grammatically correct.

Calendar custom page (embedded)

New images custom page


Such complex pages are hard to load for the browser, so the new updates brings optimizations for quicker and device-specific loading of gallery pages. For instance the skin now preloads the icon fonts and the folder image, so it loads the page with less “Flash Of Unstyled Content” from now on. The thumbnail layouts got also optimized so they don’t jump aroud while loading in Story and Photoblogger skins. I fixed the progressive load function too, which also makes the page be ready much earlier.

Cross-skin translation tool

In order to have more skins receive the most localizations I made a handy tool that gathers texts from other skins, so it saves time for translators. Also helps me finding all the texts used in the source files.

Comments are welcome,