Back to Newsfeed
Why September could be the month to rethink your property portfolio
Industry News Trending Pinned

Why September could be the month to rethink your property portfolio

Property118 · 10 Sep 2026 · 14 min read

Property118 Why September could be the month to rethink your property portfolio With September well under way and talk of an annual property tax under Prime Minister Andy Burnham, it’s no wonder landlords are once again questioning what the future holds. Under proposals previously backed by Mr Burnham, council tax and stamp duty would be replaced with an annual charge paid by property owners, reportedly equivalent to 0.48% of a property’s value. For landlords already dealing with the Renters’ Rights Act, higher costs, and increasingly demanding compliance requirements, the prospect of another annual property charge may feel like yet another reason to question whether every property in their portfolio is still worth keeping. But that doesn’t necessarily mean selling everything. At Landlord Sales Agency, we’re a company founded by landlords for landlords, so we understand that deciding whether to stay in the market or leave altogether is rarely a simple decision. Some landlords are ready to sell their entire portfolio and move on. Others still believe in property but want to sell the properties that are no longer performing as well, release some equity or reduce their exposure while keeping hold of their best investments. You don’t have to choose between keeping everything and selling everything. That is particularly important when uncertainty over tax and regulation makes it difficult to know exactly what the next few years will bring. A property that has performed brilliantly for the last 10 or 20 years may still be producing rent, but that doesn’t automatically mean it deserves a place in your portfolio for the next 10. An older property could be approaching a period when maintenance, energy-efficiency improvements or changing compliance requirements demand further investment. A heavily mortgaged property may no longer produce the return it once did. Another property may simply have reached the point where the equity tied up in it could work harder elsewhere. Doing nothing isn’t a cost-free option. The question landlords should be asking is whether the next £10,000, £20,000 or £30,000 is best invested in that property, or whether the equity already sitting in it could be put to better use. A cost isn’t the same as a loss We typically sell properties for around 85–90% of their open market value, using some of the equity to create a sale that works for everyone involved. Using equity to attract the right buyers, secure a tenant’s cooperation and open up more ways to sell isn’t simply “giving money away”. It is a cost of achieving the outcome – just as giving up nine months’ rent, spending £1,000 evicting a tenant and another £5,000 redecorating and replacing worn fittings can be costs of selling through a high street agent. The difference is where that money is being spent. Using equity can create options, keep rent coming in for most of the process and remove the need to spend thousands getting an empty property ready for sale. And that’s where having different options to sell can make all the difference. Where possible, we sell without disturbing tenants and use the equity to attract chain-free investors who can complete in 56 days. Where necessary, we can also use some of that equity to help tenants so they are happy to surrender possession voluntarily rather than the landlord having to chase possession through the courts. Our fee comes from the agreed amount, and we pay the solicitors of your choice from our list of approved, independent panel solicitors. It also covers other costs such as EPC certificates and listing materials, so there are no additional costs on top. Of course, there is nothing stopping sellers negotiating with buyers and tenants themselves to secure a faster sale and voluntary surrender. But for landlords who don’t want to manage buyers, tenants, solicitors and the sales process themselves, that’s where our experience comes in. Nobody knows exactly what future property tax changes will eventually look like, and making a rushed decision based on political speculation rarely puts a landlord in the strongest position. But uncertainty can be a good reason to look closely at what you own. Selling from a position of strength means you’re not dependent on one buyer, one route to market or one outcome. You have choices, and if your property is still generating rent, you have the time and income to choose the option that works best for you. Whether you want to sell one property, several properties or an entire portfolio, Landlord Sales Agency can look at the options with you. Before spending another £10,000, £20,000 or £30,000 on a property you’re no longer sure you want, find out what it could put in your bank instead. A no-obligation conversation with Landlord Sales Agency could give you a very different view of your options. Name * Email * Phone * Please give us details of how we can help and the properties in question * Privacy Policy * I have read and accept Property118’s Privacy Policy (function(){var el=document.getElementById("ts-607776b5-3f7b-431c-b5cc-fc304603fee3");if(!el)return;var b=document.body,h=document.documentElement;var dark=b.classList.contains("dark-mode")||b.classList.contains("dark")||b.classList.contains("night-mode")||h.classList.contains("dark");if(!dark){var bg=window.getComputedStyle(b).backgroundColor,m=bg.match(/\d+/g);if(m)dark=(m[0]*0.299+m[1]*0.587+m[2]*0.114) Submit (function(){ var uid = "crm-form-ba09a29b"; var form = document.getElementById(uid + '-form'); var wrap = document.getElementById(uid); var msg = wrap.querySelector('.crm-message'); var totalPages = 1; var curPage = 0; // ── Name casing ────────────────────────────────────────────────────── // Tidy a name box as the visitor leaves it, so they are not staring at // "JOHN SMITH" in their own form. Deliberately cosmetic: the API runs // the same normalisation on submit and is the authority on what gets // stored, so a disagreement here is harmless. Kept in step with // packages/shared/src/names.ts. var NAME_PARTICLES = ' van von de del della der den di da dal du la le el bin ibn al dos das do ter ten '; var NAME_MACS = ' macdonald macintyre macleod macarthur macgregor macneil macpherson macrae mackinnon macqueen '; function nameUp(s){ return s.replace(/[a-z]/i, function(c){ return c.toUpperCase(); }); } function isParticle(w){ return NAME_PARTICLES.indexOf(' ' + w.toLowerCase() + ' ') >= 0; } function nameRecase(atom){ if (!/[a-z]/i.test(atom)) return atom; var dot = atom.charAt(atom.length - 1) === '.' ? '.' : ''; var core = dot ? atom.slice(0, -1) : atom; var lower = core.toLowerCase(); if (/^(?:II|III|IV|VI|VII|VIII|IX|XI|XII)$/.test(core.toUpperCase())) return core.toUpperCase() + dot; if (lower === 'jr' || lower === 'sr') return nameUp(lower) + dot; if (core.length === 1) return core.toUpperCase() + dot; var mc = /^mc([a-z]{2,})$/.exec(lower); if (mc) return 'Mc' + nameUp(mc[1]) + dot; if (NAME_MACS.indexOf(' ' + lower + ' ') >= 0) return 'Mac' + nameUp(lower.slice(3)) + dot; return nameUp(lower) + dot; } function nameWellFormed(atom){ // "Mccoll" has its leading capital but still wants McColl. Safe only // because "Mc" is unambiguous — "Mac" deliberately has no such rule. if (/^Mc[a-z]{2,}$/.test(atom)) return false; return /^(?:[A-Z][a-z]*|[A-Z][a-z]+[A-Z][A-Za-z]*|O[A-Z][a-z]+|[A-Z]{1,3}|[IVX]+)$/.test(atom); } function tidyName(value){ var v = (value || '').replace(/\s+/g, ' ').replace(/^ | $/g, ''); if (!v) return value; if (/[@\d,]|&[a-z]+;|&#|https?:|www\./i.test(v)) return value; // not a name var words = v.split(' '); var deliberate = words.every(function(w){ // A lone particle is not a particle — it is someone's name (Di, Al). if (words.length > 1 && isParticle(w)) return true; return w.split(/[-'\u2019.]/).filter(function(seg){ return /[a-z]/i.test(seg); }) .every(function(seg){ return nameWellFormed(seg); }); }); if (deliberate) return v; return words.map(function(w, i){ if (i > 0 && isParticle(w)) return w.toLowerCase(); return w.split(/([-'\u2019.])/).map(function(seg){ return /^[-'\u2019.]$/.test(seg) ? seg : nameRecase(seg); }).join(''); }).join(' '); } // ── Thousand separators ────────────────────────────────────────────── // Opt-in per field (data-thousands). Mirrors formatThousands() and the // caret helpers in the CRM's packages/shared/src/numbers.ts. The CRM // strips the separators again on submit, so storage is unaffected. function groupThousands(value){ var raw = String(value == null ? '' : value).replace(/,/g, ''); if (!raw) return ''; var neg = raw.charAt(0) === '-'; var body = neg ? raw.slice(1) : raw; var dot = body.indexOf('.'); var digits = function(x){ return x.replace(/[^0-9]/g, ''); }; var whole = digits(dot === -1 ? body : body.slice(0, dot)); var frac = dot === -1 ? null : digits(body.slice(dot + 1)); if (!whole && frac === null) return neg ? '-' : ''; var grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ','); return (neg ? '-' : '') + grouped + (frac === null ? '' : '.' + frac); } // Reposition by digit count, not character index: commas appear and // vanish to the left of the caret, and counting characters would throw // it to the end of the field on every keystroke. function caretAfterGrouping(formatted, digitsBefore){ if (digitsBefore parseFloat(cmp); case 'lessthan': return parseFloat(val) [ ][ ]', so the prefix arm above // collects EVERY rendered row. Demanding all of them be filled means one blank // extra row - added by mistake, or rendered by settings.minRows - blocks Next and // Submit with a generic message on the wrapper. Only the first row is required. var firstRow = form.querySelector('[data-field-id="' + fld.id + '"] .crm-repeater-row'); if (firstRow) { reqEls = Array.prototype.filter.call(reqEls, function (el) { return firstRow.contains(el); }); } var toTest = reqEls.length ? reqEls : [els[0]]; return Array.prototype.every.call(toTest, function (el) { return (el.value || '').trim() !== ''; }); } function crmFirstInvalid(pageIdx) { for (var i = 0; i [ ][ ]". // Group those flat keys into an array of row objects under the repeater // id. Plain fields, checkbox "[]" arrays and single-bracket composites // (name[first], address[city]) don't match the double-bracket pattern, so // ordinary submissions are unchanged. var _repRe = /^(.+?)\[(\d+)\]\[(.+)\]$/; var _repIds = {}; Object.keys( data ).forEach( function ( key ) { var m = key.match( _repRe ); if ( ! m ) { return; } var rid = m[1], row = parseInt( m[2], 10 ), sub = m[3]; _repIds[ rid ] = true; if ( ! Array.isArray( data[ rid ] ) ) { data[ rid ] = []; } if ( ! data[ rid ][ row ] || typeof data[ rid ][ row ] !== 'object' ) { data[ rid ][ row ] = {}; } data[ rid ][ row ][ sub ] = data[ key ]; delete data[ key ]; } ); Object.keys( _repIds ).forEach( function ( rid ) { if ( Array.isArray( data[ rid ] ) ) { data[ rid ] = data[ rid ].filter( function ( r ) { return r && typeof r === 'object'; } ); } } ); // GF auto-substituted {user_agent} / {referer} on hidden fields // at render time. We do the equivalent right before submit so // fields whose default value carries these placeholders // resolve to the browser's actual values rather than being // stored as literal "{user_agent}" / "{referer}" strings. // The last ARTICLE the visitor read (set client-side on post views by // P118_Article_Views). Used to attribute the enquiry to the article // even after navigating away or with a stripped/absent referer. var lastPost = ''; try { var lpm = document.cookie.match(/(?:^|;\s*)p118_last_post=([^;]+)/); if (lpm) lastPost = decodeURIComponent(lpm[1]); } catch (e) {} var subs = { '{user_agent}': navigator.userAgent || '', // Prefer the last article read; fall back to the (lossy) HTTP referer. '{referer}': lastPost || document.referrer || '', '{last_post}': lastPost || '', '{embed_url}': window.location.href || '', }; for (var name in data) { if (!data.hasOwnProperty(name)) continue; var v = data[name]; if (typeof v !== 'string') continue; for (var tag in subs) { if (v.indexOf(tag) !== -1) v = v.split(tag).join(subs[tag]); } data[name] = v; } // Agent/BDM attribution — read LIVE so it works even on a fully cached // page (the browser always sees the real URL + cookie). URL ?ataid=/?cid= // first, then the 30-day agent_id/cid cookies set by atat-tracking.php. var _qp = new URLSearchParams(window.location.search); var _ataid = _qp.get('ataid') || (document.cookie.match(/(?:^|;\s*)agent_id=([^;]+)/) || [])[1] || ''; var _cid = _qp.get('cid') || (document.cookie.match(/(?:^|;\s*)cid=([^;]+)/) || [])[1] || ''; if (_ataid) data.agent_id = decodeURIComponent(_ataid); if (_cid) data.bdm_id = decodeURIComponent(_cid); // Which page the form was actually on. Read live for the same reason // as the attribution above: on a cached page the server has no idea // which URL it is being served as, but the browser always does. data._sourceUrl = window.location.href; // …and what sent them to it. Read live for the same reason: a cached // page cannot know either, but the browser does. Blank when they // typed the address, used a bookmark, or came from an email client — // which is the honest answer, not a gap to be filled in server-side. data._referrerUrl = document.referrer || ''; return data; } function uploadFiles(data) { var fileInputs = form.querySelectorAll('input[type=file][data-crm-file-field]'); var uploads = []; fileInputs.forEach(function(el) { if (!el.files || !el.files[0]) return; var fd = new FormData(); fd.append('file', el.files[0]); var fieldName = el.name; uploads.push( fetch(crmApiUrl + '/public/forms/' + "08ceeaae-4809-444e-ba0f-88da5836c463" + '/upload', { method: 'POST', body: fd }) .then(function(r) { if (!r.ok) throw new Error('File upload failed (' + r.status + ')'); return r.json(); }) .then(function(res) { if (res.path) data[fieldName] = res.path; else throw new Error(res.error || 'File upload failed'); }) ); }); return Promise.all(uploads).then(function() { return data; }); } function submitFormData(data) { var body = new FormData(); body.append('action', 'p118_crm_submit'); body.append('form_id', "08ceeaae-4809-444e-ba0f-88da5836c463"); body.append('data', JSON.stringify(data)); // Embed-page context for GF-style merge tags ({embed_url}, // {embed_post:post_title}, {embed_post:ID}). Captured PHP-side // at render time, then echoed to JS so the submit fetch can // forward to V2 as request headers. body.append('embed_url', ""); body.append('embed_post_id', "0"); body.append('embed_post_title', ""); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: body, credentials: 'same-origin' }) .then(function(r){ return r.json(); }) .then(function(res){ var p = res.data || res; if (p && p.success) { if (p.confirmationType === 'form' && p.nextFormId) { return swapInNextForm(p.nextFormId, p.prefill || {}); } if (p.confirmationType === 'redirect' && p.confirmationRedirectUrl) { window.location.href = p.confirmationRedirectUrl; } else { form.style.display = 'none'; msg.className = 'crm-message success'; msg.innerHTML = p.confirmationMessage || 'Thank you for your submission.'; // Carry the calculator's own results across. A calculator form // renders its figures into [data-iht-results] as the visitor // types; hiding the form hid those too, so the completion // screen went blank and the visitor lost what they had just // worked out. Nothing happens on forms without that element. var resultsEl = form.querySelector('[data-iht-results]'); if (resultsEl && resultsEl.innerHTML.trim()) { var carried = document.createElement('div'); carried.className = 'crm-message-results'; carried.innerHTML = resultsEl.innerHTML; msg.appendChild(carried); } // Download link for a generated report, present only when the // API filed the PDF before responding. Built through the DOM // rather than concatenated into innerHTML so the URL cannot // inject markup. if (p.reportDownloadUrl) { var dlWrap = document.createElement('p'); dlWrap.className = 'crm-report-download'; var dl = document.createElement('a'); dl.className = 'crm-report-button'; // Building through the DOM stops markup injection but not a // javascript: URL, which would run in this origin the moment // the submitter clicks the button. dl.href = /^https?:\/\//i.test(String(p.reportDownloadUrl)) ? p.reportDownloadUrl : '#'; dl.target = '_blank'; dl.rel = 'noopener noreferrer'; dl.textContent = 'Download your report (PDF)'; dlWrap.appendChild(dl); msg.appendChild(dlWrap); } msg.style.display = 'block'; if (msg.scrollIntoView) { msg.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } } else { throw new Error((p && p.error) || 'Submission failed.'); } }); } // Replace this whole form widget with another form, rendered server-side // with the carried-over values seeded in. Inline injected via // innerHTML won't run, so we re-create each script node to execute it // (this is what wires up the new form's submit / conditional logic). function swapInNextForm(nextFormId, prefill) { var rbody = new FormData(); rbody.append('action', 'p118_crm_render_form'); rbody.append('form_id', nextFormId); rbody.append('prefill', JSON.stringify(prefill || {})); return fetch("https:\/\/www.property118.com\/wp-admin\/admin-ajax.php", { method: 'POST', body: rbody, credentials: 'same-origin' }) .then(function(r){ return r.json(); }) .then(function(res2){ var pd = res2.data || res2; if (!pd || !pd.html) { throw new Error((pd && pd.error) || 'Could not load the next form.'); } var frag = document.createElement('div'); frag.innerHTML = pd.html; var parent = wrap.parentNode; var nodes = []; while (frag.firstChild) { var node = frag.firstChild; parent.insertBefore(node, wrap); nodes.push(node); } parent.removeChild(wrap); function reexec(old) { var s = document.createElement('script'); for (var a = 0; a The post Why September could be the month to rethink your property portfolio appeared first on Property118 .

Originally published by

Property118

Read full article